CSAPP:图 8-37 图 8.36 的改进版本,正确解释了信号未排队的事实

问题描述 投票:0回答:1

当我阅读第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;
}
c signals
1个回答
0
投票
  1. 为什么
    while
    有用?

常规信号不会排队,这意味着,例如,如果

SIGCHLD
被传递到已经有
SIGCHLD
待处理的进程,那么它实际上会丢失。 因此,您可能有多个终止的孩子准备好同时被收集,但只有一个
SIGCHLD
提醒您这一点。 在这种情况下,
while
可以收集所有,而带有 if
 的版本仅收集每个信号的一个子信号。

    main和handler2的并发执行流程是怎样的?
信号处理不会引入任何并发性。 信号是异步处理的,这意味着程序的常规控制流将暂时挂起,同时执行信号处理。 根据发生这种情况时程序正在执行的操作、信号处理程序(如果有)的配置方式以及其他详细信息,您可能会看到系统调用因被信号中断而失败,或者您可能看不到任何信号处理程序。中断的直接影响。

© www.soinside.com 2019 - 2024. All rights reserved.