僵尸进程是子进程终止后父进程未回收其PCB导致的伪存活状态,解决方法有四:①wait阻塞回收;②waitpid精准或非阻塞回收;③注册SIGCHLD信号处理器自动回收;④忽略SIGCHLD让内核自动清理。

僵尸进程不是“真活着”,而是子进程已终止、父进程却没及时回收其退出状态,导致内核保留PCB(进程控制块)——它不占CPU、不执行代码,但持续占用PID和进程表项。不处理,积少成多就会耗尽系统可用进程号。核心解决思路就两条:让父进程主动回收,或绕过回收直接忽略。
用wait阻塞等待一个子进程结束
wait是最基础的回收方式,调用后父进程会暂停,直到任意一个子进程终止。适合简单场景,比如单次fork后只等那个子进程。
- 传入NULL可忽略退出状态,只做资源清理
- 返回值是结束子进程的PID,失败返回-1,记得检查errno
- 一次wait只能回收一个子进程;多个子进程需循环调用
用waitpid精准回收指定子进程
waitpid比wait更灵活,能指定等待哪个子进程,还能非阻塞轮询,避免父进程被卡住。
- 第一个参数填子进程PID,填-1等同于wait(任一子进程)
- 第三个参数设为WNOHANG,函数立即返回:有子进程结束就回收,没有就返回0,不阻塞
- 配合status参数,可用WIFEXITED、WEXITSTATUS等宏解析退出码或信号
用SIGCHLD信号自动触发回收
服务器类程序常需长期运行并不断fork子进程服务客户端,手动轮询waitpid不现实。这时应注册SIGCHLD信号处理器,在子进程终止时自动调用wait或waitpid。
- 务必在fork子进程前设置signal(SIGCHLD, handler),否则可能漏掉信号
- 推荐用sigaction替代signal,能可靠设置SA_RESTART标志,避免accept等慢系统调用被中断后出错
- 信号处理函数里建议用waitpid(-1, &status, WNOHANG)循环回收,防止多个子进程同时退出时只收一个
直接忽略SIGCHLD让内核自动清理
如果父进程完全不关心子进程退出状态,最简方案是忽略SIGCHLD信号。内核检测到父进程忽略该信号后,会在子进程终止时直接回收其PCB,不产生僵尸进程。
- 调用signal(SIGCHLD, SIG_IGN)即可,无需写信号处理函数
- 注意:此法适用于子进程纯属“甩手干活”,父进程对其结果无任何依赖的场景
- 不能在子进程已启动后再设置,必须在fork之前完成

















