子进程是否也应该解除阻塞的SIGCHLD信号?
我试图理解阻塞和取消阻塞信号是如何工作的,我试图理解下面的代码。具体地说,我在看第28行(在代码中注释):子进程是否也应该解除阻塞的SIGCHLD信号?,c,signals,multiple-processes,sigprocmask,C,Signals,Multiple Processes,Sigprocmask,我试图理解阻塞和取消阻塞信号是如何工作的,我试图理解下面的代码。具体地说,我在看第28行(在代码中注释):inta=sigprocmask(SIG_UNBLOCK,&mask,NULL),亦称信号在子系统中被解锁的位置 我从教科书上得到的代码说,代码使用信号阻塞是为了确保程序在其删除功能(简化为printf(“添加%d\n”,pid);)之前执行其添加功能(简化为printf(“删除%d\n,pid);)。这对我来说很有意义;通过阻塞SIGCHLD信号,然后在执行add函数后解除阻塞,我们确保在
inta=sigprocmask(SIG_UNBLOCK,&mask,NULL)代码>,亦称信号在子系统中被解锁的位置
我从教科书上得到的代码说,代码使用信号阻塞是为了确保程序在其删除功能(简化为printf(“添加%d\n”,pid);
)之前执行其添加功能(简化为printf(“删除%d\n,pid);
)。这对我来说很有意义;通过阻塞SIGCHLD
信号,然后在执行add函数后解除阻塞,我们确保在执行add函数之前不会调用处理程序。然而,为什么我们要解除孩子体内的信号?这不就是通过立即解除阻塞消除了整个阻塞点,允许子级在父级添加之前删除吗
然而,无论我是否注释掉了行,输出(在代码后面描述)都是相同的,这意味着这显然不是发生的事情。教科书说:
请注意,子项继承其父项的阻止集,因此在调用execve
之前,必须小心解除子项中的SIGCHLD
信号的阻止
但在我看来,解除阻塞仍然会导致调用处理程序。这条线到底是干什么的
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
然而,为什么我们要解除孩子体内的信号?不是吗
只要立即解除阻塞,就可以消除整个阻塞点
是否允许在父项添加之前删除子项
不是。每个进程都有自己的信号掩码。一个新进程继承其父进程的信号掩码,但其意义与它继承父进程内存的内容相同——子进程将获得相当于一个独立副本的内容。它对该副本的修改不会反映在父副本中,子副本启动后也不会反映在父副本中。如果不是这样,那么系统中的所有进程将共享一个信号掩码
只有父级不能过早接收到SIGCLD
,因此只有父级需要阻止该信号
[……]教科书指出:
“请注意,孩子继承了他们父母的阻塞集,因此我们必须小心地在之前解除孩子中的SIGCHLD信号的阻塞
正在调用Exeve。“
但在我看来,这似乎仍然会导致
正在调用的处理程序
同样,“继承”是指继承副本,而不是共享同一掩码
这条线到底是干什么的
它在子对象中取消阻止SIGCLD
,同样对父对象没有影响,以防被阻止会干扰子对象即将执行的/bin/date
的行为。在信号处理程序中不能安全地调用printf()
。Per:标准库中的函数不保证可重入,可能会修改具有静态或线程存储持续时间的对象。and:因此,信号处理程序通常不能调用标准库函数。POSIX允许从信号处理程序调用“异步信号安全”函数,并提供一个列表printf()
不在该列表中。在信号处理程序中阻塞调用waitpid()
,例如使用waitpid(-1,NULL,0)
,也是一个坏主意<代码>while((pid=waitpid(-1,NULL,WNOHANG))>0)
要好得多-这将收获所有已退出的子进程,而不会无限期地等待任何尚未退出的子进程。如果存在尚未退出的子进程,则信号处理程序将挂起,直到它们全部退出。在子进程中取消阻止对父进程没有影响。