当我阅读第8章CSAPP中正确的信号处理时,我不太理解图8-36中的改进。在改进后的图8-37中,原书使用
while
代替if
来正确解释信号不排队的事实。
我的理解是,图8-36使用
if
来完成一个SIGCHLD,从而回收一个子进程,但这假设信号是排队的。图8-37中,使用了while
,这样就可以利用SIGCHLD一次回收多个子进程,这就是原书所说的尽可能多的回收僵尸进程。
此外,我还了解到,
handler2
程序是与主程序并发执行的,即多线程执行。对此,我不太清楚这两个程序的并发执行流程是怎样的。
我的两个问题是:
1.为什么
while
有用?
2.
main
和handler2
的并发执行流程是怎样的?
这是原始代码
/* figure 8-36 */
/* WARNING: This code is buggy! */
void handler1(int sig)
{
int olderrno = errno;
if ((waitpid(-1, NULL, 0)) < 0)
sio_error("waitpid error");
Sio_puts("Handler reaped child\n");
Sleep(1);
errno = olderrno;
}
int main()
{
int i, n;
char buf[MAXBUF];
if (signal(SIGCHLD, handler1) == SIG_ERR)
unix_error("signal error");
/* Parent creates children */
for (i = 0; i < 3; i++) {
if (Fork() == 0) {
printf("Hello from child %d\n", (int)getpid());
exit(0);
}
}
/* Parent waits for terminal input and then processes it */
if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
unix_error("read");
printf("Parent processing input\n");
while (1)
;
exit(0);
}
/* figure 8-37 An improved version of Figure 8.36 that correctly accounts for the fact that signals are not queued */
void handler2(int sig)
{
int olderrno = errno;
while (waitpid(-1, NULL, 0) > 0) {
Sio_puts("Handler reaped child\n");
}
if (errno != ECHILD)
Sio_error("waitpid error");
Sleep(1);
errno = olderrno;
}
- 为什么
有用?while
常规信号不会排队,这意味着,例如,如果
SIGCHLD
被传递到已经有 SIGCHLD
待处理的进程,那么它实际上会丢失。 因此,您可能有多个终止的孩子准备好同时被收集,但只有一个 SIGCHLD
提醒您这一点。 在这种情况下,while
可以收集所有,而带有 if
的版本仅收集每个信号的一个子信号。
信号处理不会引入任何并发性。 信号是异步处理的,这意味着程序的常规控制流将暂时挂起,同时执行信号处理。 根据发生这种情况时程序正在执行的操作、信号处理程序(如果有)的配置方式以及其他详细信息,您可能会看到系统调用因被信号中断而失败,或者您可能看不到任何信号处理程序。中断的直接影响。main和handler2的并发执行流程是怎样的?