OS / Linux / SIGCHLD 信号
一、SIGCHLD 的产生条件
- 子进程终止时。
- 子进程接收到 SIGSTOP 信号停止时。
- 子进程处在停止态,接收到 SIGCONT 后唤醒时。
也就是说:子进程的运行状态发生变化就会发送 SIGCHLD 信号;这里的意思时,子进程比较依恋父母,自己发生变化就要给父母说一下。
二、借助 SIGCHLD 信号回收子进程
子进程结束运行,其父进程会收到 SIGCHLD 信号。该信号的默认处理动作是忽略,可以捕捉该信号,在捕捉函数中完成子进程状态的回收。不多说,上代码:
#include
#include
#include
#include
#include void sys_err(const char *p)
{perror(p);exit(1);
}void do_sig_parent(int signal)
{int status;while (waitpid(0, &status, WNOHANG) > 0){if (WIFEXITED(status))std::cout << "子进程正常退出,状态:" << WEXITSTATUS(status) << std::endl;else if (WIFSIGNALED(status))std::cout << "子进程异常退出,状态:" << WTERMSIG(status) << std::endl;}return;
}int main()
{int i = 0;int pid = 0;for (; i < 10; ++i){if ((pid = fork()) == 0)break;else if (pid < 0)std::cout << "fork error" << std::endl;}if (i < 10)std::cout << "子进程的 ID:" << getpid() << std::endl;else{struct sigaction act, oldact;act.sa_handler = do_sig_parent;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask, SIGCHLD);if (sigaction(SIGCHLD, &act, &oldact) < 0)sys_err("sigaction error");while (1){std::cout << "父进程的 ID:" << getpid() << std::endl;sleep(1);}if ((sigaction(SIGCHLD, &oldact, &act)) < 0)sys_err("sigaction error");}sleep(1);return 0;
}
结果:
子进程的 ID:15185
子进程的 ID:15188
子进程的 ID:15187
子进程的 ID:15189
子进程的 ID:15191
父进程的 ID:15184
子进程的 ID:15192
子进程的 ID:15193
子进程的 ID:15186
子进程的 ID:15190
子进程的 ID:15194
子进程正常退出,状态:0
子进程正常退出,状态:0
子进程正常退出,状态:0
父进程的 ID:15184
子进程正常退出,状态:0
子进程正常退出,状态:0
父进程的 ID:15184
子进程正常退出,状态:0
子进程正常退出,状态:0
子进程正常退出,状态:0
子进程正常退出,状态:0
子进程正常退出,状态:0
父进程的 ID:15184
父进程的 ID:15184
父进程的 ID:15184
父进程的 ID:15184
父进程的 ID:15184
父进程的 ID:15184
运行正常,父进程接收到了所有的子进程的退出消息。
现在我们来提问:可不可以将程序中,捕捉函数内部的 while 替换为 if,即将代码 while((waitpid(0, &status, WNOHANG) > 0)) 换为 if((waitpid(0, &status, WNOHANG) > 0))?为什么?
答案:不可以,修改下并运行:
子进程的 ID:15384
子进程的 ID:15385
子进程的 ID:15386
子进程的 ID:15388
父进程的 ID:15383
子进程的 ID:15390
子进程的 ID:15393
子进程的 ID:15387
子进程的 ID:15392
子进程的 ID:15389
子进程的 ID:15391
子进程正常退出,状态:0
父进程的 ID:15383
子进程正常退出,状态:0
父进程的 ID:15383
子进程正常退出,状态:0
父进程的 ID:15383
父进程的 ID:15383
父进程的 ID:15383
父进程的 ID:15383
父进程的 ID:15383
父进程的 ID:15383
可以发现,有 7 个子进程的退出状态父进程没有捕获到,原因是 if 只执行一次回收(因为到了那儿说明父进程收到信号了,也就是说一定有子进程死掉了。)但是若是某一个时刻有多个子进程同时死了,那么依据信号不进行排队的原理,就只有其中一个信号被处理,其他的被忽略。但是 while 就不一样了,就算同时来多个信号,但是 while 时循环执行,虽然信号处理先后顺序不一样,但是每个信号都会被处理啊(非阻塞的 waitpid 函数)。
所以啊,当有多个子进程时,回收的时候用循环,不要用 if。
参考:https://blog.csdn.net/weixin_30752699/article/details/97366496
(SAW:Game Over!)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
