Linux中处理SIGCHLD的核心目标是及时回收子进程资源以防僵尸进程,可通过显式忽略(signal(SIGCHLD, SIG_IGN)或sigaction设SA_NOCLDWAIT)或自定义处理器配合循环waitpid(-1, &status, WNOHANG)实现。

Linux 中处理 SIGCHLD 的核心目标不是“拦截信号”,而是让子进程退出后,其资源能被及时释放——否则就会变成僵尸进程。关键不在于信号本身怎么传,而在于父进程是否做了对应的动作来回收。
显式忽略 SIGCHLD(最简洁可靠)
如果父进程完全不需要知道子进程的退出码或运行时长,直接告诉内核“别通知我,你来收尾”是最省心的方式:
- 调用 signal(SIGCHLD, SIG_IGN) 即可(Linux 下有效且行为明确)
- 或者用 sigaction 设置 SA_NOCLDWAIT 标志,效果等价
- 此时子进程终止后,内核自动完成清理,不会留下僵尸,也不触发信号处理函数
自定义信号处理器 + 循环 waitpid(需获取退出状态时用)
当需要读取子进程退出码、判断是否异常终止等,就得自己动手回收。但必须注意:不能只调用一次 wait 或 waitpid:
- 在信号处理函数中,用 waitpid(-1, &status, WNOHANG) 循环调用,直到返回 0(无子进程可收)
- WNOHANG 确保非阻塞,避免父进程卡住
- 不能用 wait(),它无法指定选项,也无法安全循环;也不能只调用一次,因为多个子进程可能几乎同时退出,而 SIGCHLD 不排队,一次处理可能漏掉几个
避开常见坑点
很多僵尸问题其实源于实现细节疏忽:
- 信号处理函数里避免调用 printf、malloc 等非异步信号安全函数
- 不要在 fork 后立刻 exit,却不等子进程——这容易让子进程短暂变孤儿再变僵尸(除非父进程也很快退出)
- 使用 systemd 托管的服务,默认已启用子进程自动回收,一般无需额外处理 SIGCHLD
本质上,SIGCHLD 只是通知机制,真正决定僵尸是否产生的,是父进程有没有执行回收动作。忽略它或正确响应它,都能防住僵尸;放任不管,哪怕只漏收几次,积累起来就成问题。











