CSAPP信号程序测试问题:fork()执行后父进程无法从STDIN读取输入
问题原因
- 信号处理函数阻塞主流程执行
你在handler2末尾添加了sleep(1000)调用,信号处理函数执行期间会挂起主进程的正常执行逻辑。3个子进程退出会触发至少2次SIGCHLD信号处理,每次处理都会等待1000秒,此期间主流程的read调用一直被挂起,无法响应用户输入。 - 未处理系统调用被中断的异常
Ubuntu 16.04中signal函数注册信号处理函数时,默认不会开启SA_RESTART标志。read属于慢速系统调用,当它在阻塞等待输入时被SIGCHLD信号中断,会直接返回-1并将errno设置为EINTR,你当前的代码未对该错误做重试处理,会直接触发错误退出逻辑。
解决方案
- 删除信号处理函数中的
sleep调用sleep不属于异步信号安全函数,且超长等待完全阻塞了主流程执行,直接删除handler1和handler2中的sleep(1000);语句即可。 - 为
read调用添加EINTR重试逻辑
修改read调用的判断逻辑,被信号中断时自动重试:
while ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0) { if (errno != EINTR) { unix_error("read"); } // 被信号中断,重试读取 }
- (可选)使用
sigaction注册信号并开启系统调用自动重启
如果希望被信号中断的慢速系统调用自动恢复执行,可以用sigaction代替signal注册处理函数,开启SA_RESTART标志:
struct sigaction sa; sa.sa_handler = handler2; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { unix_error("sigaction error"); }
内容的提问来源于stack exchange,提问作者mingming
相关产品推荐
相关产品推荐

