信号入门
1.生活中的信号
-
你在网上买了很多件商品,在等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时,你该怎么处理快递,也就是你能 “识别快递”
-
当快递员到了你楼下,你也收到快递到来的通知,但是此时你正在打游戏,需 5min 之后才能去取快递。那么在在这 5min 之内,你并没有下去去取快递,但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行,可以理解成 “在合适的时候去取”
-
在收到通知,再到你拿到快递期间,是有一个时间窗口的,在这段时间内,你并没有拿到快递,但是你知道有一个快递已经来了。本质上是你 “记住了有一个快递要去取”。
-
当你时间合适,顺利拿到快递之后,就要开始处理快递了。而处理快递一般方式有三种:1、执行默认动作(幸福的打开快递,使用商品);2、 执行自定义动作(快递是零食,你要送给你你的女朋友);3. 忽略快递(快递拿上来之后,扔掉床头,继续开一把游戏)。
-
快递到来的整个过程对你来讲是异步的,你不能准确断定快递员什么时候给你打电话。
生活中存在大量的信号,如下课铃、红绿灯、发令枪、闹钟、外卖电话…、
a.我们是怎么认识这些信号的呢?有人教我们认识这些信号,并且告诉我们处理这些信号的方法;
b. 即使是我们现在没有信号产生,我也知道信号产生之后,我应该干什么;
c. 信号产生了,我们可能并不立即处理这个信号,在合适的时候,因为我们可能正在做更重要的事情。
那么同样,在Linux系统中的进程也需要具备如下能力:
-
进程必须能够识别+处理信号
-
进程即使没有收到信号,也要知道哪些信号该怎么处理
-
进程真的收到了一个具体的信号的时候,进程可能不会立即处理这个信号,而是在合适的时候;
-
在进程收到信号,到信号开始被处理,一定会存在一个窗口期,进程具有临时保存哪些信号已经发生了的能力
进程处理信号的方式有三种:1️⃣ 默认动作;2️⃣ 自定义动作;3️⃣ 忽略;
2.技术应用角度的信号
(1)用户输入命令,在 Shell 下启动一个前台进程。
用户按下 Ctrl+C,这个键盘输入产生一个硬件中断,被 OS 获取,解释成信号,发送给目标前台进程。前台进程因为收到信号,进而引起进程退出。
将生活例子和 Ctrl+C 信号处理过程相结合,解释一下信号处理过程:进程就是你,操作系统就是快递员,信号就是快递。
注意
-
Ctrl+C 产生的信号只能发给前台进程。一个命令后面加个 & 可以放到后台运行,这样 Shell 不必等待进程,结束就可以接受新的命令,启动新的进程。
-
Shell 可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl+C 这种控制键产生的信号。
-
前台进程在运行过程中用户随时可能按下 Ctrl+C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的。
3.信号的基本概念
信号(Signal)是操作系统用来通知进程某些事件发生的机制,属于异步通信的一种方式。信号机制最初是在UNIX系统中引入的,并广泛用于现代类UNIX操作系统(如Linux)。当某个进程或系统事件触发信号时,信号会传递给目标进程,目标进程可以根据接收到的信号作出相应处理。信号常用于异常处理、进程控制、进程间通信等场景
信号的特点
1.异步性:信号的发送和接收是异步的。进程可以在任何时刻收到信号,不需要主动检查某种状态。
2.软中断:信号类似于软中断,系统或进程可以通过信号来通知其他进程某个事件的发生,进程可以对信号作出响应。
3.轻量级:与进程间通信(如管道、消息队列、共享内存)相比,信号是一种轻量级的通信机制。
信号的分类
1.标准信号:这是系统预定义的一组信号,通常表示特定的系统事件或异常情况;也就是1-31号信号
我们可以通过 kill -l 查看所有信号
其中每个信号都有一个编号和一个宏定义名称,这些宏定义可以在 signal.h 中找到,例如其中有定义 #define SIGINT 2
2.实时信号:除了标准信号外,Linux还支持实时信号(Real-time Signals)编号34以上的信号,用于更细粒度的进程通信和控制。实时信号具有更高的优先级,可以携带更多的信息,并且其顺序在内核中得到保证。
我们不讨论实时信号,这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明:man 7 signal
4.信号处理常见方式概览
sigaction 函数后面会详细介绍),可选的处理动作有以下四种:
-
默认处理(SIG_DFL):操作系统对每个信号都有默认处理方式。例如接收到SIGKILL时,进程会立即终止。
-
自定义处理:进程可以通过设置信号处理函数,改变系统默认的处理方式。例如接收到SIGINT时,程序可以捕获信号并进行清理操作后再退出。
-
忽略信号(SIG_IGN):
-
可以将信号设置为忽略,这样当信号到达时,进程不会采取任何操作。
-
例如,将SIGINT(中断)设置为忽略可以阻止
Ctrl + C
中断程序。
-
-
阻塞信号:进程可以选择阻塞某些信号,阻塞期间不会处理这些信号,直到解除阻塞。
5.信号的发送与保存
信号的发送(Signal Delivery)
-
产生信号:信号可以由多种方式产生,包括用户输入(如
ctrl + c
)、系统事件(如硬件故障)或程序内部(如程序运行出错)。 -
发送信号:信号发送者(通常是另一个进程或内核)将信号发送给信号接收者(目标进程)。
-
信号处理:目标进程接收到信号后,可以执行信号处理程序。这通常是通过调用信号处理函数(signal handler)来实现的。
-
信号阻塞:在信号发送和处理过程中,进程可能会阻塞某些信号,这可以防止信号在特定时刻被处理。
信号的保存(Signal Preservation)
-
信号掩码:信号掩码是一个位掩码,用于控制信号的阻塞。它包含了一个或多个信号的掩码位,当这些位被设置时,对应的信号将被阻塞。
-
信号处理程序:信号处理程序是在信号发送时调用的函数,用于处理信号。在信号发送之前,当前信号处理程序的状态会被保存,以便信号处理程序执行完毕后能够恢复。
-
信号集:信号集是一个结构,用于保存当前阻塞的信号集合。当信号发送时,如果信号在信号集中,则信号将被阻塞,直到信号集被更新。
-
信号屏蔽字:信号屏蔽字是一个整数,用于保存当前阻塞的信号集合。当信号发送时,如果信号在屏蔽字中,则信号将被阻塞。
-
信号状态:信号状态包括信号掩码、信号集和信号屏蔽字。这些状态在信号发送和处理过程中被保存和恢复。
1-31信号的作用
有少部分编号不一定与man 7 signal 顺序一致,因为系统版本问题,我们知道每个信号有什么用题即可,信号编号可查
信号编号 | 信号名称 | 用途 |
---|---|---|
1 | SIGHUP | 表示终端挂断(hang-up)事件。当终端会话结束时发送给进程。 |
2 | SIGINT | 表示中断信号(interrupt)。通常由键盘中断键(如Ctrl + C )发送。 |
3 | SIGQUIT | 表示退出信号(quit)。通常由键盘退出键(如Ctrl + \ )发送。 |
4 | SIGILL | 表示非法指令信号(illegal instruction)。当进程尝试执行非法指令时发送。 |
5 | SIGTRAP | 表示跟踪信号(trap)。当进程请求调试跟踪时发送。 |
6 | SIGABRT | 表示进程终止信号(abort)。通常由abort() 函数发送。 |
7 | SIGEMT | 表示设备不可用信号(emulate)。通常由simulate() 函数发送。 |
8 | SIGFPE | 表示浮点异常信号(floating-point exception)。当发生浮点异常时发送。 |
9 | SIGKILL | 表示终止信号(kill)。发送此信号将直接终止进程,没有机会进行清理。 |
10 | SIGBUS | 表示总线错误信号(bus error)。当总线错误发生时发送。 |
11 | SIGSEGV | 表示段错误信号(segmentation fault)。当进程尝试访问非法内存区域时发送。 |
12 | SIGSYS | 表示系统调用失败信号(bad argument to system call)。当系统调用参数错误时发送。 |
13 | SIGPIPE | 表示管道破裂信号(broken pipe)。当进程写入到已关闭的管道时发送。 |
14 | SIGALRM | 表示定时器信号(alarm clock)。当定时器到期时发送。 |
15 | SIGTERM | 表示终止信号(terminate)。通常用于优雅地终止进程。 |
16 | SIGURG | 表示紧急信号(urgent condition on socket)。当套接字上有紧急数据时发送。 |
17 | SIGSTOP | 表示停止信号(stop)。发送此信号将停止进程的执行。 |
18 | SIGTSTP | 表示停止信号(stop typed at terminal)。当用户在终端上键入停止字符时发送。 |
19 | SIGCONT | 表示继续信号(continue)。发送此信号将恢复停止的进程的执行。 |
20 | SIGCHLD | 表示子进程终止信号(child status has changed)。当子进程终止时发送。 |
21 | SIGTTIN | 表示后台输入信号(stop typed at terminal)。当后台进程尝试从终端读取时发送。 |
22 | SIGTTOU | 表示后台输出信号(stop typed at terminal)。当后台进程尝试向终端写入时发送。 |
23 | SIGIO | 表示输入输出请求信号(I/O request)。当I/O请求到达时发送。 |
24 | SIGXCPU | 表示超出CPU时间限制信号(CPU time limit exceeded)。当进程超出CPU时间限制时发送。 |
25 | SIGXFSZ | 表示超出文件大小限制信号(file size limit exceeded)。当进程试图创建或写入超过文件大小限制的文件时发送。 |
26 | SIGVTALRM | 表示虚拟定时器信号(virtual timer alarm)。当虚拟定时器到期时发送。 |
27 | SIGPROF | 表示性能定时器信号(profiling timer alarm)。当性能定时器到期时发送。 |
28 | SIGWINCH | 表示窗口大小改变信号(window size change)。当终端窗口大小改变时发送。 |
29 | SIGINFO | 表示状态信息信号(status request)。当进程请求状态信息时发送。 |
30 | SIGUSR1 | 用户定义信号1(User-defined signal 1)。由程序员定义用途 |
31 | SIGUSR2 | 用户定义信号2(User-defined signal 2)。由程序员定义用途。 |