在 Linux 下用 fork 创建子进程很容易,但如果子进程退出后父进程不管不顾,"僵尸进程"就会找上门。它们占着 PID、耗资源,甚至可能让系统无法新建进程。
进程等待正是解决这一问题的核心机制。它不仅能回收子进程资源,还能获取子进程的退出状态(正常结束?被信号终止?)。从 wait 的基础阻塞等待,到 waitpid 的精细化控制(指定子进程、非阻塞监听),再到解析 status 参数的退出信息,这些都是写出健壮 Linux 程序的必备技能。
为什么需要进程等待
进程等待的必要性可以分为两类场景:
-
必须解决:清理僵尸进程 僵尸进程的状态为
Z。它的数据、代码会被内核自动清理,但 PCB(进程控制块)会残留 PID、退出状态、调度信息等属性,持续占用系统资源,且无法通过kill -9直接杀死。只有父进程通过进程等待,才能彻底回收 PCB 资源。如果父进程退出,子进程会成为孤儿进程被系统进程(init/systemd)回收,但这通常不是我们想要的可控行为。 -
可选关注:获取子进程的退出状态 通过进程等待,父进程可以拿到子进程的退出信息(比如是正常完成任务,还是被信号中断),以此判断子进程的任务执行结果。这一步可根据业务需求选择是否关注,但对需要确保任务可靠性的场景至关重要。
wait 函数基础
wait 函数是 Linux 系统中一类进程控制函数,其作用是让父进程以阻塞方式等待任意一个子进程终止,同时完成该子进程的资源回收与退出状态获取。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
- 返回值:成功返回被等待进程的 PID,失败返回 -1。
- 参数:
status是输出型参数,用于获取子进程退出状态。如果不关心退出状态,可以设置为NULL。
场景一:等待单个子进程(仅回收资源)
在这个场景中,父进程创建子进程后,子进程循环几次就退出进入僵尸状态;父进程继续执行自身任务,待完成后调用 wait 阻塞回收已处于僵尸状态的子进程。
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main() {
pid_t id = fork();
(id < ) {
perror();
;
}
(id == ) {
cnt = ;
(cnt) {
(, getpid(), getppid(), cnt);
cnt--;
sleep();
}
();
} {
cnt = ;
(cnt) {
(, getpid(), getppid(), cnt);
cnt--;
sleep();
}
ret = wait();
(ret > ) {
(, ret);
}
sleep();
}
;
}


