我正在阅读https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551,在那里,作者在处理程序中处理调用waitpid而不是wait的sigchld。
在图5.7中的
中,我们不能在循环中调用wait,因为如果还没有终止运行的子程序,就无法阻止wait阻塞。
处理程序如下:
void sig_chld(int signo)
{
pid_t pid;
int stat;
// while ((pid = wait(&stat)) > 0)
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
{
printf("child %d terminated\n", pid);
}
}问题是,即使我使用阻塞版本的wait (如注释掉的那样),子程序无论如何也会被终止(这就是我想要的,以便没有僵尸),那么为什么还要考虑它是以阻塞方式还是非阻塞方式呢?
如果是非阻塞方式(即使用waitpid),那么我可以多次调用处理程序吗?(当一些儿童被终止,而另一些仍在运行时)。但是,我仍然可以阻止并在处理程序中等待所有的子程序终止。因此,多次调用处理程序或只调用一次没有区别。或者还有其他原因需要多次非阻塞和调用处理程序吗?
发布于 2021-01-01 20:42:10
while循环条件将比需要等待的僵尸子进程多运行一次。因此,如果您使用wait()而不是带有WNOHANG标志的waitpid(),那么如果您有另一个仍在运行的子进程,它可能会永远阻塞--因为wait()只会在没有子进程的情况下提前返回ECHLD错误。健壮的泛型处理程序将使用waitpid()来避免这种情况。
想象一个例子,其中父进程启动多个子进程来执行各种事情,并定期向他们发送有关该做什么的指令。当第一个进程退出时,在SIGCHLD处理程序中使用循环中的SIGCHLD将导致它永久阻塞,而其他子进程则在等待更多他们永远不会接收到的指令。
或者,比如说,一个inetd服务器,它侦听网络连接并分叉一个新进程来处理每个进程。有些服务完成得很快,有些可以运行几个小时或几天。如果它使用一个信号处理程序来捕获退出的子程序,那么如果在一个循环中使用wait(),那么它将无法做任何其他事情,除非在一个循环中使用该处理程序,因为该处理程序是由一个短期服务进程退出的。
发布于 2021-01-01 21:19:08
我花了一秒钟时间才明白是什么问题,所以让我把它说出来。正如其他人所指出的,wait(2)可能会阻止。如果指定了waitpid(2)选项,WNOHANG将不会阻塞。
您正确地说,对wait(2)的第一次调用不应阻止,因为只有当子程序退出时,才会调用信号处理程序。但是,当信号处理程序被调用时,可能已经退出了几个子处理程序。信号是异步传送的,并且可以合并。因此,如果两个子进程在接近同一时间退出,操作系统可能只向父进程发送一个信号。因此,必须使用循环来迭代地检查是否有多个子节点已退出。
既然我们已经确定了该循环对于检查是否有多个子级退出是必要的,那么显然我们不能使用wait(2),因为如果有一个未退出的子程序,那么它将在第二次迭代中阻塞。
TL;DR循环是必要的,因此使用waitpid(2)是必要的。
https://stackoverflow.com/questions/65533328
复制相似问题