为什么要使用 non-blocking waitpid 而不是阻塞等待?
Why to use non-blocking waitpid instead of blocking wait?
我正在阅读 https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551,作者在那里处理调用 waitpid
而不是 wait
的处理程序中的 sigchld
。
In Figure 5.7, we cannot call wait in a loop, because there is no way to prevent wait from blocking if there are
running children that have not yet terminated.
处理程序如下:
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
的阻塞版本(如注释掉的那样),child 无论如何都会终止(这是我想要的,以便没有僵尸), 那么为什么还要考虑它是 blocking 方式还是 non-blocking?
我假设它是 non-blocking 方式(即使用 waitpid
),那么我可以多次调用处理程序吗? (当some childs被终止,而other仍然是运行)。但我仍然可以在该处理程序中阻塞并等待 all child 终止。因此,多次调用处理程序或仅调用一次处理程序之间没有区别。还是有其他原因 non-blocking 并多次调用处理程序?
while 循环条件将 运行 比需要等待的僵尸进程 child 多一次。因此,如果您使用 wait()
而不是 waitpid()
和 WNOHANG
标志,如果您还有另一个 运行ning child - 作为 wait()
只有 returns 早,如果根本没有 child 进程,则会出现 ECHLD
错误。一个健壮的通用处理程序将使用 waitpid()
来避免这种情况。
想象这样一种情况,其中 parent 进程启动多个 children 来做各种事情,并定期向他们发送有关做什么的指令。当第一个退出时,在 SIGCHLD
处理程序的循环中使用 wait()
将导致它永远阻塞,而其他 child 进程则等待更多它们永远不会的指令收到。
或者说,一个 inetd
服务器侦听网络连接并派生一个新进程来处理每个连接。有些服务可以很快完成,有些可以 运行 数小时或数天。如果它使用信号处理程序来捕获退出的 children,那么在 long-lived 退出之前,如果您在循环中使用 wait()
一旦该处理程序是由 short-lived 服务进程退出触发。
我花了一秒钟才明白问题出在哪里,所以让我把它说清楚。正如其他人所指出的,wait(2)
可能会阻塞。如果指定了 WNOHANG
选项,waitpid(2)
将不会阻塞。
你说 first 调用 wait(2)
不应该阻塞是正确的,因为只有在 child 退出时才会调用信号处理程序.但是,当调用信号处理程序时,可能有几个 children 可能已经退出。信号是异步传递的,并且可以合并。因此,如果两个 children 几乎同时退出,则操作系统可能只向 parent 进程发送一个信号。因此,必须使用循环来迭代检查是否有多个 child 退出。
现在我们已经确定循环对于检查多个 children 是否已经退出是必要的,很明显我们不能使用 wait(2)
因为它会在第二个阻塞如果有 child 还没有退出,则进行迭代。
TL;DR 循环是必要的,因此使用 waitpid(2)
是必要的。
我正在阅读 https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551,作者在那里处理调用 waitpid
而不是 wait
的处理程序中的 sigchld
。
In Figure 5.7, we cannot call wait in a loop, because there is no way to prevent wait from blocking if there are running children that have not yet terminated.
处理程序如下:
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
的阻塞版本(如注释掉的那样),child 无论如何都会终止(这是我想要的,以便没有僵尸), 那么为什么还要考虑它是 blocking 方式还是 non-blocking?
我假设它是 non-blocking 方式(即使用 waitpid
),那么我可以多次调用处理程序吗? (当some childs被终止,而other仍然是运行)。但我仍然可以在该处理程序中阻塞并等待 all child 终止。因此,多次调用处理程序或仅调用一次处理程序之间没有区别。还是有其他原因 non-blocking 并多次调用处理程序?
while 循环条件将 运行 比需要等待的僵尸进程 child 多一次。因此,如果您使用 wait()
而不是 waitpid()
和 WNOHANG
标志,如果您还有另一个 运行ning child - 作为 wait()
只有 returns 早,如果根本没有 child 进程,则会出现 ECHLD
错误。一个健壮的通用处理程序将使用 waitpid()
来避免这种情况。
想象这样一种情况,其中 parent 进程启动多个 children 来做各种事情,并定期向他们发送有关做什么的指令。当第一个退出时,在 SIGCHLD
处理程序的循环中使用 wait()
将导致它永远阻塞,而其他 child 进程则等待更多它们永远不会的指令收到。
或者说,一个 inetd
服务器侦听网络连接并派生一个新进程来处理每个连接。有些服务可以很快完成,有些可以 运行 数小时或数天。如果它使用信号处理程序来捕获退出的 children,那么在 long-lived 退出之前,如果您在循环中使用 wait()
一旦该处理程序是由 short-lived 服务进程退出触发。
我花了一秒钟才明白问题出在哪里,所以让我把它说清楚。正如其他人所指出的,wait(2)
可能会阻塞。如果指定了 WNOHANG
选项,waitpid(2)
将不会阻塞。
你说 first 调用 wait(2)
不应该阻塞是正确的,因为只有在 child 退出时才会调用信号处理程序.但是,当调用信号处理程序时,可能有几个 children 可能已经退出。信号是异步传递的,并且可以合并。因此,如果两个 children 几乎同时退出,则操作系统可能只向 parent 进程发送一个信号。因此,必须使用循环来迭代检查是否有多个 child 退出。
现在我们已经确定循环对于检查多个 children 是否已经退出是必要的,很明显我们不能使用 wait(2)
因为它会在第二个阻塞如果有 child 还没有退出,则进行迭代。
TL;DR 循环是必要的,因此使用 waitpid(2)
是必要的。