Linux通过SIGCHLD信号异步通知父进程子进程已退出,内核保留其进程描述符直至父进程调用wait类函数回收;忽略该信号会导致僵尸进程,而显式处理或设为SIG_IGN(Linux 2.6+)可避免。

Linux 通过 SIGCHLD 信号自动通知父进程子进程已退出。这不是父进程轮询或主动查询的结果,而是内核在子进程终止(无论正常退出还是被信号杀死)时,**立即向其父进程异步发送 SIGCHLD**,属于操作系统内核级的进程间通信机制。
核心机制:SIGCHLD 是默认触发的“退出提醒”
当子进程调用 exit()、_exit(),或因收到信号(如 SIGKILL、SIGSEGV)而终止时,内核会:
- 回收该子进程的大部分资源(如用户栈、寄存器上下文等);
- 但**保留其进程描述符(task_struct)和退出状态信息**,直到父进程明确获取;
- 同时向父进程发送
SIGCHLD信号 —— 这是唯一专用于子进程状态变更的信号。
父进程必须处理 SIGCHLD,否则会残留僵尸进程
如果父进程对 SIGCHLD 不做任何响应(既不捕获也不忽略),系统将采用默认行为:**忽略该信号**。但关键点在于:忽略 SIGCHLD 并不等于清理子进程。此时子进程变成僵尸进程(Z 状态),其退出状态仍驻留在内核中,占用进程表项。
- 正确做法是安装信号处理函数,在其中调用
wait()或waitpid(-1, ..., WNOHANG)来非阻塞地收割已退出的子进程; - 也可直接忽略:
signal(SIGCHLD, SIG_IGN)—— 自 Linux 2.6 起,此操作会让内核**自动回收子进程**,避免僵尸,但父进程无法得知具体哪个子进程退出、为何退出。
信号处理 + wait 系列函数才是完整闭环
仅注册 SIGCHLD 处理器还不够。信号本身只起“提醒”作用,真正完成清理和状态读取的是 wait 类函数:
-
wait(NULL):阻塞等待任意一个子进程结束; -
waitpid(pid, &status, WNOHANG):非阻塞检查指定子进程是否已退出; - 配合宏判断状态:
WIFEXITED(status)、WEXITSTATUS(status)、WIFSIGNALED(status)、WTERMSIG(status)。
典型模式是在信号处理函数中循环调用 waitpid(-1, &status, WNOHANG),直到返回 -1(表示当前无已退出子进程待收),确保一次 SIGCHLD 可能对应多个子进程退出时不会遗漏。
与显式等待(wait)的区别和共存
父进程也可以不依赖信号,直接在关键位置调用 wait() 主动阻塞等待。但这种方式缺乏实时性,且无法应对“多子进程异步退出”的场景。实际工程中常二者结合:
- 用
SIGCHLD实现异步通知; - 在信号处理函数中用
waitpid(..., WNOHANG)完成即时清理; - 主逻辑中仍可按需调用
waitpid()同步等待特定子进程,例如启动服务后等待其初始化完成。











