为什么sigprocmask用于阻止SIGCHLD在以下代码中提供

q09*_*987 6 c linux multiprocessing ubuntu-10.04

基于http://man7.org/tlpi/code/online/book/procexec/multi_SIGCHLD.c.html

int
main(int argc, char *argv[])
{
    int j, sigCnt;
    sigset_t blockMask, emptyMask;
    struct sigaction sa;

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s child-sleep-time...\n", argv[0]);

    setbuf(stdout, NULL);       /* Disable buffering of stdout */

    sigCnt = 0;
    numLiveChildren = argc - 1;

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigchldHandler;
    if (sigaction(SIGCHLD, &sa, NULL) == -1)
        errExit("sigaction");

    /* Block SIGCHLD to prevent its delivery if a child terminates
       before the parent commences the sigsuspend() loop below */

    sigemptyset(&blockMask);
    sigaddset(&blockMask, SIGCHLD);
    if (sigprocmask(SIG_SETMASK, &blockMask, NULL) == -1)
        errExit("sigprocmask");

    for (j = 1; j < argc; j++) {
        switch (fork()) {
        case -1:
            errExit("fork");

        case 0:         /* Child - sleeps and then exits */
            sleep(getInt(argv[j], GN_NONNEG, "child-sleep-time"));
            printf("%s Child %d (PID=%ld) exiting\n", currTime("%T"),
                    j, (long) getpid());
            _exit(EXIT_SUCCESS);

        default:        /* Parent - loops to create next child */
            break;
        }
    }

    /* Parent comes here: wait for SIGCHLD until all children are dead */

    sigemptyset(&emptyMask);
    while (numLiveChildren > 0) {
        if (sigsuspend(&emptyMask) == -1 && errno != EINTR)
            errExit("sigsuspend");
        sigCnt++;
    }

    printf("%s All %d children have terminated; SIGCHLD was caught "
            "%d times\n", currTime("%T"), argc - 1, sigCnt);

    exit(EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)

这是我的理解:

sigprocmask(SIG_SETMASK,&blockMask,NULL)

调用进程的结果信号集应该是blockMask指向的集合.

为什么我们说下面的陈述?

如果子进程在父进程开始下面的sigsuspend()循环之前终止,则阻止SIGCHLD阻止其传递

换句话说,我不明白为什么sigprocmask用于根据sigprocmask语句的给定描述来阻止SIGCHLD.

Nem*_*emo 9

好吧,我认为评论很清楚......

每当你调用fork()并想以任何方式与孩子互动时,都需要考虑竞争条件.如果孩子在父母之前跑了一段时间怎么办?或相反亦然?

在这种情况下,无法知道父母将在呼叫之后接听fork电话的时间sigsuspend.那么如果分叉的孩子完成它sleepexit在父母调用之前调用sigsuspend呢?然后父母将收到一个SIGCHLD它忽略的......然后它会调用sigsuspend,它将永远不会返回因为SIGCHLD已经被传递.

唯一的100%解决方案是SIGCHLD 调用之前fork阻塞,然后在入口处以原子方式解锁它sigsuspend.(处理这种竞争条件正是为什么sigsuspend需要信号掩码作为参数...如果你在呼叫之前尝试解锁信号sigsuspend,就会出现竞争状态;即信号可能在你开始等待之前被传递.改变信号mask然后输入wait必须是原子的,你必须阻止你想要等待的任何信号才能生成它.)