问题:
一个unp中第五章的例子:有5个客户端几乎同时向服务器发送终止连接,这时在服务器端将几乎同时产生SIGCHILD信号,然而信号在内核中是不排队的,信号处理函数只执行一次(我的理解是5个信号几乎同时到达,当第一个信号被处理时,其他4个信号是未决的,当信号处理函数处理完第一个到达的信号后,由于没有产生信号,信号处理函数将不会被再次调用)。那么在目前情况下,父进程怎样才能捕获到所有的子进程的退出状态呢?
分析:
在SIGCHLD的handler中添加如下代码显然不行:
void
sig_chld(int signo)
{
pid_t pid;
int stat;
pid = wait(&stat);
printf("child %d terminated\n", pid);
return;
}
因为使用wait时,它只等到第一个SIGCHLD到达的子进程,之后就如上所示return了。在信号处理函数只能执行一次的前提下,其他4个SIGCHLD信号就没有被处理。
而如果在handler中使用如下的方式就可以:
void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
原因分析如下:在while循环中使用waitpid的非阻塞模式(WNOHANG),当第一个信号到达时,printf然后回到while继续waitpid,接着第二个信号到达,依次处理,直到这5个信号都被处理完之后,根据WNOHANG常量的说明“The waitpid function will not block if a child specified by pid is not immediately available. In this case, the return value is 0. ”(见APUE2中8.6节),所以waitpid将返回0,跳出while循环,这样子进程的终止状态都被捕获到了,父进程继续做它的事。
总结:
wait与waitpid的主要区别:
(1)waitpid能够等指定pid的子进程;而wait只能等第一个到达的子进程。
(2)waitpid通过指定WNOHANG可以不阻塞,没有可用的子进程就立即返回0;而wait要求父进程一直阻塞。
上面这两点其实就是waitpid比wait多了1、3两个参数。
补充:
查看源码,wait就是包装过的waitpid,include/unistd.h
static inline pid_t wait(int * wait_stat)
{
return waitpid(-1,wait_stat,0);
}