编程与 AI14 分钟阅读更新于 2026-08-04

Linux 信号怎么工作:进程通知、默认动作与信号处理

解释 Linux 信号的作用、发送来源、默认动作和自定义处理方式,并梳理 SIGHUP、SIGPIPE、SIGURG 等常见信号与进程状态变化的关系。

相关工具

信号是给进程的异步通知

信号可以理解为操作系统、用户或其他进程发给目标进程的一种短消息。它通常只表达一件事:某种状态发生了,进程需要采取默认动作或进入自己的处理逻辑。信号不是一段长数据,也不是替代管道和消息队列的数据传输通道。

信号到达的时间通常由事件决定,而不是由目标进程主动安排。进程正在运行、睡眠或等待 I/O 时,都可能留下待处理信号。系统会在合适的执行时机检查并处理它,因此信号天然带有异步通知的特点。

信号从触发来源经过内核投递到目标进程处理的流程图
信号从事件到进程处理

用户、内核或其他进程触发信号,内核记录目标进程状态,进程随后执行默认动作或自定义处理。

谁可以发送信号

用户可以通过终端操作或管理工具向进程发送信号,例如请求终止、暂停或继续运行。一个进程也可以在满足权限条件时向另一个进程发送信号,用于协作、取消任务或通知状态变化。

内核也会因为硬件异常、资源状态或设备事件产生信号。例如进程执行非法内存访问时,系统可能向它发送 SIGSEGV;终端挂起、管道读端关闭和套接字异常,也可能触发相应信号。信号来源不同,但最终都由内核负责记录和投递。

默认动作决定信号的第一反应

每种信号通常都有一个默认动作。常见默认动作包括终止进程、终止并生成用于分析的核心转储、暂停进程,或让暂停的进程继续运行。默认动作让系统在进程没有特别设置时仍然能够对异常和控制请求作出反应。

默认动作不是信号名称的全部含义。同一个信号可能被程序捕获并改写处理方式,也可能被忽略,少数信号则不能被忽略或自定义处理。理解一个信号时,应同时看它的触发场景、默认动作和程序是否设置了处理函数。

信号到达后根据处理设置分为默认动作、自定义处理和忽略的分支图
信号的处理分支

信号到达后,进程可以执行默认动作、进入自定义处理,或在允许的情况下忽略信号。

SIGHUP 为什么不只是“挂起”

SIGHUP 最初和终端挂起有关。当终端连接结束或控制终端发生变化时,相关进程可能收到 SIGHUP。对于长期运行的程序,它常被用作“原来的控制端消失了”的通知,程序可以选择退出、重新加载配置或执行清理动作。

具体行为由程序决定,不能把 SIGHUP 简单等同于任何一种固定操作。一个服务收到 SIGHUP 后重新读取配置,是应用约定出来的用法;另一个程序可能直接采用默认动作退出。信号只提供通知,业务含义要看接收方如何解释。

SIGPIPE 如何暴露断开的写端

当进程向已经没有读取方的管道或连接写入数据时,系统可能产生 SIGPIPE。它提醒写入方:数据没有可以继续接收的对端。默认情况下,这类信号可能导致进程终止,避免程序在明确失去对端后还不断写入。

网络程序通常需要认真处理这种情况。程序可以捕获或忽略 SIGPIPE,再通过写操作的返回结果判断连接是否已经关闭。这样可以把“对端消失”纳入正常的连接清理流程,而不是让整个进程因为一次写入直接退出。

SIGURG 为什么和套接字有关

SIGURG 用于通知进程套接字连接上出现了紧急数据。它并不代表普通数据已经完整到达,也不代替应用层协议的解析。程序收到通知后仍然需要通过相应的套接字操作查看状态和读取数据。

这类信号说明信号可以作为设备或通信状态变化的提醒,但提醒本身携带的信息很少。需要传递大量内容时,仍应使用管道、队列、共享内存或套接字缓冲,而不是试图把数据塞进信号。

信号处理函数里为什么不能做太多事

信号可能在程序执行任意位置时到达。处理函数运行时,原来的代码被暂时打断,某些库内部状态可能正处于中间阶段。如果在处理函数中调用复杂、可能再次加锁或依赖不稳定状态的操作,容易产生重入问题。

更稳妥的做法通常是记录一个简单标志、写入一个安全的通知管道,或使用系统允许在信号上下文中执行的有限操作,把复杂工作留给主事件循环。信号处理函数越短,越容易保证原有程序状态能够安全恢复。

信号处理函数通过标志或通知唤醒主循环完成复杂工作的流程图
信号处理与主循环协作

信号处理函数只记录事件,主循环在安全上下文中完成配置重载、连接清理或任务取消。

信号和进程状态如何配合

有些信号会让进程暂停,有些信号会让暂停中的进程继续,有些信号则请求进程终止。信号本身不等于进程状态,但它可以触发状态变化。调度器随后根据进程是否可运行、是否等待资源等条件,决定何时再次安排它执行。

父进程还可能通过等待机制了解子进程是否退出、暂停或继续。这样,信号负责推动变化,进程状态和等待接口负责让其他进程观察结果。把“发送信号”和“确认处理完成”区分开,才能避免误以为信号发出就代表目标动作已经结束。

用一条主线理解 Linux 信号

事件发生后,用户、内核或其他进程向目标进程产生信号;内核根据权限和目标状态完成投递;目标进程在合适时机处理信号,执行默认动作、忽略它或进入自定义处理;处理结果可能改变进程状态,也可能只是留下一个待处理标志。

学习信号时,可以依次问:是谁触发的,通知的是什么事件,默认动作是什么,程序能否改变处理方式,处理函数是否足够短,以及其他进程如何确认结果。这样,SIGHUP、SIGPIPE、SIGURG 和内存访问异常就能放进同一个通知模型中理解。

常见问题

信号可以用来传递大量数据吗?

不适合。信号主要表达状态或事件通知,数据量很小;大量数据应使用管道、消息队列、共享内存或套接字。

所有信号都可以被捕获或忽略吗?

不是。部分信号不能被忽略或自定义处理,其他信号是否捕获、忽略或采用默认动作取决于程序设置。

发送信号后能立刻知道目标进程完成处理吗?

不能仅凭发送动作确认。信号表示通知已经产生,目标何时处理、是否改变状态以及是否完成后续工作,需要通过其他状态或进程间通信观察。