eg1:
// waitpid1.c
// 2015-08-26 Lucifer Zhang
// Using the waitpid function to reap zombie children in no
// particular order.
#include "csapp.h"
#define N 2
int main()
{
int status, i;
pid_t pid;
/* Parent creates N children */
for (i = 0; i < N; i++) //line:ecf:waitpid1:for
if ((pid = Fork()) == 0) /* child */ //line:ecf:waitpid1:fork
exit(100+i); //line:ecf:waitpid1:exit
/* Parent reaps N children in no particular order */
while ((pid = waitpid(-1, &status, 0)) > 0) { //line:ecf:waitpid1:waitpid
if (WIFEXITED(status)) //line:ecf:waitpid1:wifexited
printf("child %d terminated normally with exit status=%d\n",
pid, WEXITSTATUS(status)); //line:ecf:waitpid1:wexitstatus
else
printf("child %d terminated abnormally\n", pid);
}
/* The only normal termination is if there are no more children */
if (errno != ECHILD) //line:ecf:waitpid1:errno
unix_error("waitpid error");
exit(0);
}
第15行,父进程创建N个子进程,在第16行,每个子进程以一个唯一的退出状态退出。在第19行,父进程用waitpid作为while循环的测试条件,等待它所有的子进程终止,因为第一个参数是-1,所以对waitpid的调用会阻塞,知道任意一个子进程终止。在每个子进程终止时,对waitpid的调用会返回,返回值为该子进程的非零PID。第20行检查子进程的退出状态。如果子进程是正常终止的,在此是以调用exit函数终止的,那么父进程就提取出退出状态,把它输出到stdout上。
当回收了所有的子进程之后,再调用waitpid就返回-1,并且设置errno为ECHILD。第28行检查waitpid函数是正常终止的,否则就输出一个错误消息。
测试:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyM3cTN1YDM1EjNygDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
注意,程序不会按照特定的顺序回收子进程。子进程回收的顺序是这台特定的计算机的属性。在另一个系统上,甚至在同一个系统上再次执行一次,两个子进程都可能以相反的顺序被回收。上面的测试结果也说明了这一点。这是非确定性的(nondeterministic)行为的一个示例,这种非确定性行为使得对并发进行推理非常困难。
下面这个例子做了简单的改变,消除了不确定性,按照父进程创建子进程的相同顺序来回收这些子进程。
eg2:
// waitpid1.c
// 2015-08-26 Lucifer Zhang
// Using waitpid to reap zombie children in the order they were created.
#include "csapp.h"
#define N 2
int main()
{
int status, i;
pid_t pid;
/* Parent creates N children */
for (i = 0; i < N; i++) //line:ecf:waitpid1:for
if ((pid = Fork()) == 0) /* child */ //line:ecf:waitpid1:fork
exit(100+i); //line:ecf:waitpid1:exit
/* Parent reaps N children in no particular order */
while ((pid = waitpid(-1, &status, 0)) > 0) { //line:ecf:waitpid1:waitpid
if (WIFEXITED(status)) //line:ecf:waitpid1:wifexited
printf("child %d terminated normally with exit status=%d\n",
pid, WEXITSTATUS(status)); //line:ecf:waitpid1:wexitstatus
else
printf("child %d terminated abnormally\n", pid);
}
/* The only normal termination is if there are no more children */
if (errno != ECHILD) //line:ecf:waitpid1:errno
unix_error("waitpid error");
exit(0);
}