信号的概念
信号(Signal)是一种软件中断,比如Ctrl+C的退出命令实质上就是使用了信号。信号在Linux操作系统中提供了一种处理异步事件的方法,可以很好地在多个进程之间进行同步和简单的数据交互。
常见的进程信号
信号代号 | 信号名称 | 说明 |
1 | SIGHUP | 用于报告用户终端已断开连接,可能是因为网络连接中断。该信号还用于向与该会话关联的作业报告终端上控制进程的终止; 此终止有效地将会话中的所有进程与控制终端断开连接。例如将tty终端断开,即发送SIGHUP信号。 |
2 | SIGINT | 程序中止信号,用于中止前台进程。相当于输出 Ctrl+C 快捷键 |
8 | SIGFPE | 在发生致命的算术运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为 0 等其他所有的算术运算错误 |
9 | SIGKILL | 用来立即结束程序的运行。本信号不能被阻塞、处理和忽略。一般用于强制中止进程 |
14 | SIGALRM | 时钟定时信号,计算的是实际的时间或时钟时间。alarm 函数使用该信号 |
15 | SIGTERM | 正常结束进程的信号,kill 命令的默认信号。如果进程已经发生了问题,那么这个信号是无法正常中止进程的,这时我们才会尝试 SIGKILL 信号,也就是信号 9 |
18 | SIGCONT | 该信号可以让暂停的进程恢复执行。本信号不能被阻断 |
19 | SIGSTOP | 该信号可以暂停前台进程,相当于输入 Ctrl+Z 快捷键。本信号不能被阻断 |
信号的产生
Linux中信号可以由以下几种方式产生:
- 当用于按下某些终端按键之后引发终端产生的信号,例如在程序运行中按下“Ctrl + \”(ctrl c , ctrl z)组合键将终止程序的运行。
- 硬件产生的一个异常信号,例如除数为0,无效的内存引用等,这种异常信号通常会由硬件检测得到并将其通知Linux内核,然后内核为该条件发生时正在运行的进行产生适当的信号。
- 进程调用系统调用kill函数可以给一个进程或者进程组发送一个信号,需要注意的是此时发送和接收信号的进行/进程组的所有者必须相同
- 用户也可以调用kill命令将信号发送给其它进程
- 当检测到某种软件条件已经发生,并应将其通知有关进程的时候也会产生一个信号,例如SIGURG信号就是在接收到一个通过网络传送的外部数据时产生的。
信号的处理方式
Linux的每一个信号都有一个缺省的动作,典型的缺省动作是终止进程,当一个信号到来的时候收到这个信号的进程会根据信号的具体情况提供以下三种不同的处理方式:
- 类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
- 忽略某个信号,对该信号不做任何处理,就像从未发生过一样。
- 对该信号的处理保留系统的默认值,这种缺省操作大多数是使得进程终止。进程通过系统调用signal函数来指定进程对某个信号的处理行为。
信号的执行过程
一个典型的执行过程是使用“Ctrl + C”组合键来中断一个车进程的运行,对其操作部分说明如下,需要注意的是只有在前台运行的程序才能接收到“Ctrl + C"组合键的输入:
01)用户输入命令,在Shell下启动一个前台进程。
02)用户按下“Ctrl + C”,这个键盘输入产生一个硬件中断。
03)如果处理器当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU从用户态切换到内核台处理硬件中断。
04)终端驱动程序将“Ctrl + C“解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了一个SIGINT信号给该进程)。
05) 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止进程,所以直接终止进程,而不再返回它的用户空间代码。