背景:在读unix网络编程卷1, 第五章服务器处理SIGCHLD信号时。及多个客户端同时关闭socket连接,服务端主进程的多个子进程几乎同时结束。
使用wait 的情况:
void sig_chld(int signo) { pid_t pid; int stat; pid = wait(&stat); return; }
当服务端采用并发处理客户端的请求时,客户进程关闭连接,服务端子进程几乎同时结束,信号处理函数在使用wait时,并不能完全的防止僵尸进程的出现,问题在于,信号处理函数在处理第一个进程的SIGCHLD信号时,后面的四个进程也发来了SIGCHLD信号,但是信号是不排队的,这样就会导致信号丢失,这样会产生很多的僵尸进程。书中的解决办法是采用waitpid 循环判断。
采用waitpid:
void sig_chld(int signo) { pid_t pid; int stat; while((pid = waitpid(-1, &stat, WNOHANG)) > 0){ printf("child %d terminated ", pid); } return; }
看到这段代码,开始陷入了困惑,在sig_chld执行期间,后面的信号不也被忽略了吗? 为什么能防止僵尸进程? 其实不是这样的,waitpid 当第一个参数为-1 时,表示等待任何子进程,参数WNOHANG表示非阻塞wait。该函数循环等待所有的子进程,man手册的关于该函数的返回值也讲的很清楚,如果成功,返回子进程的id。当指定了WNOHANG 并且有一个或者多个子进程仍然存在,并且进程状态没有改变,即返回0. 因此sig_chld只要触发了,就会一直循环,直到所有的子进程都被处理。