我正在尝试了解阻塞和解除阻塞信号的工作原理,并且我正在尝试理解以下代码。具体来说,我正在查看第 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