8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

waitpid() 如何获得多个子进程?

crow16384 2月前

38 0

在此示例中,取自 CSAPP 书籍第 8 章:\#include \'csapp.h\'/* 警告:此代码有缺陷!\*/void handler1(int sig){int olderrno = errno; if ((waitpid(-1, NULL, 0)) < ...

这是来自 CSAPP 书第 8 章的一个例子:


\#include "csapp.h"

/* WARNING: This code is buggy! \*/

void handler1(int sig)
{
int olderrno = errno;

    if ((waitpid(-1, NULL, 0)) < 0)
        sio_error("waitpid error");
    Sio_puts("Handler reaped child\n");
    Sleep(1);
    errno = olderrno;

}

int main()
{
int i, n;
char buf[MAXBUF];

    if (signal(SIGCHLD, handler1) == SIG_ERR)
        unix_error("signal error");
    
    /* Parent creates children */
    for (i = 0; i < 3; i++) {
        if (Fork() == 0) {
            printf("Hello from child %d\n", (int)getpid());
            exit(0);
        }
    }
    
    /* Parent waits for terminal input and then processes it */
    if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
        unix_error("read");
    
    printf("Parent processing input\n");
    while (1)
        ;
    
    exit(0);

}

它生成以下输出:

......
Hello from child 14073
Hello from child 14074
Hello from child 14075
Handler reaped child
Handler reaped child //more than one child reaped
......

使用的 if 块 waitpid() 用于生成 waitpid() 无法收获所有子进程的错误。 While I understand that waitpid() is to be put in a while() loop to ensure reaping all children, what I don't understand is that why only one waitpid() call is made, yet was able to reap more than one children(Note in the output more than one child is reaped by handler)? 根据这个答案: 为什么信号处理程序中的 waitpid 需要循环? waitpid() 只能收获一个子进程。

谢谢!

更新: 这无关紧要,但处理程序通过以下方式进行更正(也取自 CSAPP 书):

void handler2(int sig) 
{
    int olderrno = errno;

    while (waitpid(-1, NULL, 0) > 0) {
        Sio_puts("Handler reaped child\n");
    }
    if (errno != ECHILD)
        Sio_error("waitpid error");
    Sleep(1);
    errno = olderrno;
}

在我的 Linux 计算机上运行此代码。

帖子版权声明 1、本帖标题:waitpid() 如何获得多个子进程?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由crow16384在本站《sockets》版块原创发布, 转载请注明出处!
最新回复 (0)
  • IIUC:如果一个子进程在信号处理程序期间退出,则会有一个排队的 SIGCHLD,它会在第一个信号处理程序返回时立即传送(一些用户空间代码会执行 sigreturn(2) 系统调用以让内核知道)。因此,即使循环决定停止循环后子进程退出,也不会出现竞争条件。但如果在该窗口期间有两个子进程退出,则仍然只有一个 SIGCHLD,因此需要一个循环。并且该设计可以避免竞争条件,因为它会排队一个待处理信号。

  • 循环是必要的,因为如果两个或多个子进程几乎同时退出,您可能会同时收到一个 SIGCHLD。这几乎与调度无关,这是因为信号不会排队(除非您专门设置它们,但我认为对于内核生成的 SIGCHLD 不可能这样做)。

  • while 循环始终是正确的方法,但是这并不影响多个子进程是否被收割的结果。原因正如最初的答案中提到的那样。实际上,错误部分更多地与不正确的调度有关,您可能会遇到只有 3 个子进程中的 2 个被收割的情况。最后一种情况可以通过使用 sleep 调用“人为地”缓解。

  • 您指定的信号处理程序每​​次 SIGCHLD 收到您分配给它的信号(在本例中)时都会运行。虽然 waitpid 每次收到信号时只执行一次,但处理程序仍会执行多次,因为每次子进程终止时都会调用它。

    子进程 n 终止( SIGCHLD ),处理程序立即采取行动并用来 waitpid “收割”刚刚退出的子进程。

    子进程 n+1 终止,其行为与子进程 n 相同。每个子进程都会重复此过程。

    没有必要循环它,因为它仅在需要时才会被调用。

    编辑:正如下面指出的那样,书中后来用预期的循环来纠正它的原因是,如果多个子级同时发送终止信号,处理程序最终可能只会得到其中一个。

    信号(7) :

    标准信号不排队。如果在信号被阻塞时生成了多个标准信号实例,则只有一个信号实例被标记为待处理(并且该信号在解除阻塞时只会被传送一次)。

    循环 waitpid 确保收获所有退出的子进程,而不是像现在这样只收获其中一个。

    为什么循环可以解决多信号的问题?

    想象一下:您当前位于处理程序内部,处理 SIGCHLD 收到的信号,在执行此操作的同时,您会收到来自在此期间已终止的其他子进程的更多信号。这些信号无法排队。通过不断循环 waitpid ,您可以确保即使处理程序本身无法处理发送的多个信号, waitpid 仍会在不断运行时拾取它们,而不是仅在处理程序激活时运行,这取决于信号是否已合并。

    waitpid 一旦没有更多子节点需要收割,循环仍然会正确退出。重要的是要理解,循环只是为了捕获当您已经处于信号处理程序中时发送的信号,而不是在正常代码执行期间发送的信号,因为在这种情况下,信号处理程序将照常处理它。

    如果您仍有疑问,请尝试阅读这两个问题的答案。

    第一个使用诸如的标志 WNOHANG ,但 waitpid 如果没有子进程准备好被收割,这只会立即返回而不是等待。

返回
作者最近主题: