我试图了解阻塞和解除阻塞信号的工作方式,并且试图理解以下代码。具体来说,我正在看第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
答案 0 :(得分:1)
但是,为什么我们要取消阻止孩子的信号?那不是吗 只是通过立即解除阻塞来消除整个阻塞点 它,允许孩子在父母添加之前删除?
不。每个过程都有自己的信号掩码。一个新进程继承了其父进程的信号掩码,但仅在继承父进程的内存内容的同义意义上,子进程就等于独立副本。对该副本的修改不会反映在父母的副本中,也不会在孩子开始之后反之亦然。如果不是这种情况,那么系统中的所有进程将共享一个信号掩码。
只有父级不能太早收到const state = this.props.location.state || { dataRef: "foo" }
,因此只有父级才需要阻止该信号。
[...]教科书指出:
“注意,孩子继承了被阻止的父母集合,因此我们必须小心在孩子之前取消阻止SIGCHLD信号 调用execve。”
但是在我看来,解锁仍然会导致 处理程序被调用。
同样,在继承副本的意义上是“继承”,而不是在共享相同的掩码的意义上。
此行的确切作用是什么?
它会取消阻止SIGCLD
在子级中运行-对父级没有任何影响-如果被阻止会干扰即将执行子级的SIGCLD
的行为。