Linux 进程信号详解:产生方式与闹钟机制
1. 理解信号的本质
1.1 什么是信号?
信号(Signal)是 Linux 系统中用于通知进程发生了某种事件的机制。它本质上是一种异步通知。想象一下你点了外卖,然后继续打游戏,外卖小哥敲门是一个通知,告诉你外卖到了。你和外卖小哥之间没有同步等待关系,这就是异步。
在操作系统中,信号也是类似的。进程在运行时,可能会收到来自内核或其他进程的通知,比如用户按下了 Ctrl+C,或者程序发生了除零错误。这些事件的发生与进程当前的执行流不同步,因此需要一种机制来记录和处理这些事件。
1.2 信号的分类
通过 kill -l 命令可以查看系统支持的信号列表。通常我们关注的是 1 到 31 号普通信号,以及 34 到 64 号的实时信号(Real-time Signals)。
- 普通信号:1~31 号。这是最常用的部分。
- 实时信号:34~64 号。支持排队,可靠性更高。
1.3 信号的处理方式
当进程收到一个信号时,有三种默认的处理动作:
- 默认处理(Default):例如 SIGKILL 会直接终止进程,SIGSEGV 会生成核心转储文件。
- 忽略(Ignore):进程选择无视该信号。
- 自定义捕捉(Custom):进程注册了一个信号处理函数,收到信号后执行特定逻辑。
值得注意的是,信号不会立即被处理。如果进程正在执行高优先级任务,它会先保存信号状态,等到合适的时机再处理。因此,每个进程的 PCB(进程控制块)中都需要有一个位图来临时保存收到的信号。
2. 信号的产生方式
操作系统负责将信号写入目标进程的 PCB 位图中。主要有以下几种产生方式:
2.1 使用系统命令
最常用的是 kill 命令。它可以向指定 PID 的进程发送信号。
kill -9 <pid>
底层实际上调用了 kill() 系统调用。注意,某些信号(如 SIGKILL, 9 号)是不可捕捉、不可忽略的,这保证了系统始终有能力终止进程。
2.2 键盘输入
当你按下组合键时,终端驱动会将硬件中断转换为信号发送给前台进程组。
- Ctrl+C:发送 SIGINT(2 号),通常用于终止前台进程。
- Ctrl+Z:发送 SIGTSTP(20 号),用于暂停前台进程。
这里涉及到**作业控制(Job Control)**的概念。在一个会话(Session)中,同一时刻只能有一个进程组处于前台,能够接收键盘输入。后台进程无法直接获取键盘输入,否则会触发暂停。
2.3 系统调用
除了外部命令,程序内部也可以通过系统调用主动发送信号:
raise(sig):当前进程给自己发送信号。abort():发送 SIGABRT(6 号),用于异常终止。即使设置了捕捉,最终进程仍会终止并可能生成 core dump。
2.4 异常产生
当程序运行出现严重错误时,内核会自动产生信号:
- 段错误(Segmentation Fault):访问非法内存地址,触发 SIGSEGV(11 号)。
- 浮点异常:如除以零,触发 SIGFPE(8 号)。
这些异常信号通常会导致进程终止,除非有专门的信号处理函数介入。


