child 进程是否也应该解锁阻塞的 SIGCHLD 信号?

Should child processes also be unblocking blocked SIGCHLD signals?

我正在尝试了解阻塞和解除阻塞信号的工作原理,并且正在尝试理解以下代码段。具体来说,我正在查看第 28 行(在代码中注释):int a = sigprocmask(SIG_UNBLOCK, &mask, NULL);,也就是 child.

中信号畅通的地方

我得到代码的教科书说代码使用信号阻塞以确保程序在删除功能(简化为[=15=)之前执行其添加功能(简化为printf("adding %d\n", pid);) ]).这对我来说很有意义;通过阻塞 SIGCHLD 信号,然后在执行 add 函数后解除阻塞,我们确保在执行 add 函数之前不会调用处理程序。但是,为什么我们要解封child中的信号呢?这不是通过立即解除阻塞来消除整个阻塞点,允许 child 在 parent 添加之前删除吗?

但是,无论我是否注释掉该行,输出(在代码后描述)都是相同的,这意味着显然不是这样。课本上说:

"Notice that children inherit the blocked set of their parents, so we must be careful to unblock the SIGCHLD signal in the child before calling execve."

但在我看来,解除阻塞仍然会导致调用处理程序。这条线到底是做什么的?

void handler(int sig) {
    pid_t pid;
    printf("here\n");
    while ((pid = waitpid(-1, NULL, 0)) > 0); /* Reap a zombie child */
    printf("deleting %d\n", pid); /* Delete the child from the job list */
}

int main(int argc, char **argv) {
    int pid;
    sigset_t mask;
    signal(SIGCHLD, handler);
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &mask, NULL); /* Block SIGCHLD */

    pid = fork();
    if (pid == 0) {
        printf("in child\n");

        int a = sigprocmask(SIG_UNBLOCK, &mask, NULL); // LINE 28

        printf("a is %d\n",a);
        execve("/bin/date", argv, NULL);
        exit(0);
    }

    printf("adding %d\n", pid);/* Add the child to the job list */
    sleep(5);
    printf("awake\n");

    int b = sigprocmask(SIG_UNBLOCK, &mask, NULL);
    printf("b is %d\n", b);
    sleep(3);

    exit(0);
}

输出:

adding 652

in child

a is 0

Wed Apr 24 20:18:04 UTC 2019

awake

here

deleting -1

b is 0

However, why would we unblock the signal in the child? Doesn't that just eliminate the whole point of blocking by immediately unblocking it, allowing the child to delete before the parent adds?

没有。每个进程都有自己的信号掩码。新进程继承其 parent 的信号掩码,但仅在继承 parent 内存内容的相同意义上——child 获得相当于一个独立进程的内容复制。它对该副本的修改不会反映在 parent 的副本中,也不会在 child 启动后 反之亦然 。如果不是这种情况,那么系统中的所有进程将共享一个信号掩码。

只有 parent 不能太早收到 SIGCLD,所以只有 parent 需要屏蔽该信号。

[...] The textbook states:

"Notice that children inherit the blocked set of their parents, so we must be careful to unblock the SIGCHLD signal in the child before calling execve."

但在我看来,解锁仍然会导致 正在调用处理程序。

同样,"inherit" 是在继承副本的意义上,而不是在共享相同掩码的意义上。

What exactly does this line do?

它解除了 child 中 SIGCLD 的阻塞——同样,对 parent 没有影响——以防它被阻塞会干扰 [=12= 的行为],child 即将执行。