wait & waitpid 有什么用

2021.4.6 字节实习一面,面试官在考察我操作系统知识时,在我回答“父进程调用 wait 可以防止子进程僵尸进程出现” 后,追问我 “那操作系统为什么要这么设计,而不是在子进程退出之后就直接将其视为退出,而不是僵尸进程”。当时没答出来,面试结束后我查阅了相关的资料,对 wait 有了进一步的了解。

曾经在学习《Unix系统编程》的时候接触到 wait 和 waitpid 的概念,并且还做了笔记,只不过当时对这两个系统调用的理解还不是很深。

wait 的作用是给父进程监听子进程状态的改变的:

  • 进程被 terminate
  • 进程被 suspend
  • 进程从 suspend 中恢复

对于 terminate 的情况,执行 wait 可以让系统释放子进程的相关资源,否则子进程就会变成僵尸状态。当一个进程成为僵尸状态时,内核会存储该进程的一些信息,如 PID、终止状态、资源使用信息。这是为了等待父进程晚些时候执行 wait 来获取子进程的状态。如果这个父进程提前退出,则 init 进程会负责起执行 wait 的责任。

也就是说,一个进程可能会经历僵尸状态,时间长短取决于父进程调用 wait 是否及时。当父进程退出之后,一个僵尸进程会变成孤儿进程,由 init 来执行 wait。由于僵尸进程已经退出,所以无法 kill 掉。

总之一句话,wait & waitpid 可以让父进程获取子进程的状态变化,在获知子进程退出状态后,系统内核会回收子进程的相关资源。


下面是一个测试,子进程退出后,父进程未调用 wait 回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main()
{
pid_t cpid, w;
cpid = fork();
if (cpid == 0)
{
printf("Child PID is %ld\n", (long)getpid());
}
else
{
pause();
}
}

可以看到,[a.out] 为 Z 状态

1
2
3
 4938 14758 14758 14758 pts/0    28627 Ss       0   0:00              |       |   \_ /bin/bash
14758 28627 28627 14758 pts/0 28627 S+ 0 0:00 | | | \_ ./a.out
28627 28628 28627 14758 pts/0 28627 Z+ 0 0:00 | | | \_ [a.out] <defunct>