本文最后更新于56 天前,其中的信息可能已经过时,如有错误请发送邮件到2156936367@qq.com
信号的本质
信号是Linux系统中用于进程间通信(IPC)的一种机制,本质上是一种软件中断。它模拟了硬件中断的机制,通知进程发生了某个事件。
还是拿 “取快递”这件事来举例吧
- 信号识别(内置能力)
- 快递员打电话过来,你不需要别人教你怎么接电话,这是你的本能
- 内核在创建进程(fork)时,PCB(进程控制块)中就已经有了一张映射表,规定了数字 2 代表 SIGINT,数字 9 代表 SIGKILL 等。
- 信号产生
- 可以是快递员打电话过来,也可以是手机的快递短信…….
- 硬件层面就是键盘CTRL+C,软件层面就是kill命令…..
- 信号保存(重点)
- 当快递员打电话过来的时候,你开了把GO,1v5残局,抽不开时间接电话,等打完再去取快递
- 信号不是发给进程就立刻执行的,而是先保存在进程的 PCB 中。
- 未决信号集(Pending):收到了信号,但还没处理。
- 阻塞信号集(Blocked/Mask):进程告诉内核“我现在不方便处理这个信号,先留着别打断我”。
- 注意:阻塞不等于忽略。阻塞是“延后处理”,忽略是“直接丢弃”。
- 信号处理时机
- 打完了,就去取快递
- 进程从内核态切换回用户态的前一刻。
信号的三种处理方式
- 默认动作(Default):
- 大多数信号(如 SIGINT)的默认动作是终止进程。
- 部分是忽略(如 SIGCHLD)。
- 部分是生成 Core Dump(核心转储,如 SIGSEGV 段错误),用于事后调试。
- 忽略(Ignore):
- 明确告诉内核:“这个信号来了直接丢掉,别烦我”。
- 死穴:SIGKILL (9) 和 SIGSTOP (19) 不能被忽略,这是上帝视角(管理员)的最后手段。
- 捕捉/自定义(Capture/Handler):
- 写一个函数,通过 signal() 或 sigaction() 注册给内核。信号来了,暂停主程序,跑去执行这个函数。
- 就是修改PCB里面的那张映射表,添加一个信号和对应处理动作
常见信号表
| 信号编号 | 名称 | 常用场景/含义 | 默认动作 | 面试考点/备注 |
|---|---|---|---|---|
| 2 | SIGINT | Ctrl + C | 终止 | 友好的终止,进程可以捕获它做清理工作(如保存文件)。 |
| 3 | SIGQUIT | Ctrl + \ | Core Dump | 比 Ctrl+C 狠一点,终止并生成 Core 文件供调试。 |
| 9 | SIGKILL | kill -9 | 强制终止 | 不可捕捉、不可忽略、不可阻塞。立即杀死,进程无法做清理工作(可能导致数据丢失)。 |
| 11 | SIGSEGV | 非法内存访问 | Core Dump | 指针越界、野指针、访问空指针时产生。 |
| 15 | SIGTERM | kill | 终止 | 默认的 kill 信号。程序可以捕获它,优雅地退出(释放资源后自杀)。 |
| 17 | SIGCHLD | 子进程状态改变 | 忽略 | 子进程结束时发给父进程。父进程若不处理(调用 wait),子进程会变成僵尸进程。 |
| 19 | SIGSTOP | kill -19 | 暂停 | 不可捕捉、不可忽略。类似把程序“冻结”。 |
| 20 | SIGTSTP | Ctrl + Z | 暂停 | 这种暂停是可以被进程捕获处理的。 |
补充
- 为什么 SIGKILL (9) 和 SIGSTOP (19) 无法被捕获?
- 这是操作系统设计者留给系统管理员(Root)的“后门”或“尚方宝剑”。如果所有信号都能被进程捕获并忽略,写一个死循环病毒并忽略所有信号,那管理员就无法杀掉这个失控的进程,系统只能重启。
- kill 命令是杀进程吗?
- kill 命令的本质是向进程发送信号。
- kill <pid> 默认发送 15号信号 (SIGTERM),告诉进程“请你自己结束”。
- kill -9 <pid> 发送 9号信号 (SIGKILL),是内核直接动手杀人,不给进程喘息机会。
CTRL+C 发生了什么
按下 Ctrl+C,本质是硬件中断触发操作系统将输入转换为 SIGINT 信号,并发送给前台进程,最终导致进程终止的过程。
以下是详细过程:
1. 硬件输入(敲键盘) 当你按下 Ctrl + C,键盘给 CPU 发送了一个硬件中断,告诉 CPU:“有按键输入了,快来看!”
2. 系统解析(翻译) 操作系统的终端驱动程序拿到了这个输入,发现是 Ctrl + C 组合键。 系统知道这个组合键不是普通的字符,而是中断命令。于是,它把这个命令“翻译”成了一个信号:2号信号 SIGINT。
3. 信号发送(找目标) 操作系统把 SIGINT 信号发送给当前终端的前台进程(就是你屏幕上正在运行的那个程序)。
4. 进程处理(执行) 进程收到了 SIGINT 信号:
- 默认情况:直接终止运行(挂掉)。
- 自定义情况:如果你代码里写了捕获函数(Handler),就执行你的函数(比如清理垃圾、保存进度后再退出)。
kill -USR1和kill -USR2
在操作系统内核层面,SIGUSR1 和 SIGUSR2 没有任何区别,操作系统对它们的默认处理方式都是直接终止进程 它们都是用户自定义信号(User-defined Signal),它们的区别完全取决于程序员在写代码时,给这两个信号绑定了什么功能。

