子进程也应该解除阻塞的SIGCHLD信号吗?

时间:2019-04-24 20:36:37

标签: c signals multiple-processes sigprocmask

我试图了解阻塞和解除阻塞信号的工作方式,并且试图理解以下代码。具体来说,我正在看第28行(在代码中有注释):int a = sigprocmask(SIG_UNBLOCK, &mask, NULL);,又名信号在孩子中不受阻碍。

我从中获得代码的教科书上说,代码使用信号阻塞功能,以确保程序在其删除功能(简化为printf("adding %d\n", pid);之前执行其添加功能(简化为printf("deleting %d\n", pid);) 。这对我来说很有意义;通过阻塞SIGCHLD信号,然后在执行add函数之后将其解除阻塞,我们确保在执行add函数之前不会调用处理程序。但是,为什么我们要取消阻止孩子的信号呢?

难道不是通过立即取消阻止来消除整个阻止点,允许孩子在父项添加之前删除吗?

但是,无论我是否注释掉该行,输出(在代码后进行描述)都是相同的,这意味着显然不会发生什么。教科书指出:

  

“请注意,孩子继承了被阻止的父母集合,因此在调用SIGCHLD之前,我们必须小心解除孩子中的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

1 个答案:

答案 0 :(得分:1)

  

但是,为什么我们要取消阻止孩子的信号?那不是吗   只是通过立即解除阻塞来消除整个阻塞点   它,允许孩子在父母添加之前删除?

不。每个过程都有自己的信号掩码。一个新进程继承了其父进程的信号掩码,但仅在继承父进程的内存内容的同义意义上,子进程就等于独立副本。对该副本的修改不会反映在父母的副本中,也不会在孩子开始之后反之亦然。如果不是这种情况,那么系统中的所有进程将共享一个信号掩码。

只有父级不能太早收到const state = this.props.location.state || { dataRef: "foo" } ,因此只有父级才需要阻止该信号。

  

[...]教科书指出:

     
    

“注意,孩子继承了被阻止的父母集合,因此我们必须小心在孩子之前取消阻止SIGCHLD信号     调用execve。”

  
     

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

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

  

此行的确切作用是什么?

它会取消阻止SIGCLD在子级中运行-对父级没有任何影响-如果被阻止会干扰即将执行子级的SIGCLD的行为。