OS / Linux / SIGCHLD 信号
一、SIGCHLD 的產(chǎn)生條件
也就是說:子進(jìn)程的運行狀態(tài)發(fā)生變化就會發(fā)送 SIGCHLD 信號;這里的意思時,子進(jìn)程比較依戀父母,自己發(fā)生變化就要給父母說一下。
二、借助 SIGCHLD 信號回收子進(jìn)程
子進(jìn)程結(jié)束運行,其父進(jìn)程會收到 SIGCHLD 信號。該信號的默認(rèn)處理動作是忽略,可以捕捉該信號,在捕捉函數(shù)中完成子進(jìn)程狀態(tài)的回收。不多說,上代碼:
#include <iostream> #include <sys/types.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h>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 << "子進(jìn)程正常退出,狀態(tài):" << WEXITSTATUS(status) << std::endl;else if (WIFSIGNALED(status))std::cout << "子進(jìn)程異常退出,狀態(tài):" << 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 << "子進(jìn)程的 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 << "父進(jìn)程的 ID:" << getpid() << std::endl;sleep(1);}if ((sigaction(SIGCHLD, &oldact, &act)) < 0)sys_err("sigaction error");}sleep(1);return 0; }結(jié)果:
子進(jìn)程的 ID:15185 子進(jìn)程的 ID:15188 子進(jìn)程的 ID:15187 子進(jìn)程的 ID:15189 子進(jìn)程的 ID:15191 父進(jìn)程的 ID:15184 子進(jìn)程的 ID:15192 子進(jìn)程的 ID:15193 子進(jìn)程的 ID:15186 子進(jìn)程的 ID:15190 子進(jìn)程的 ID:15194 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 父進(jìn)程的 ID:15184 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 父進(jìn)程的 ID:15184 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 子進(jìn)程正常退出,狀態(tài):0 父進(jìn)程的 ID:15184 父進(jìn)程的 ID:15184 父進(jìn)程的 ID:15184 父進(jìn)程的 ID:15184 父進(jìn)程的 ID:15184 父進(jìn)程的 ID:15184運行正常,父進(jìn)程接收到了所有的子進(jìn)程的退出消息。
現(xiàn)在我們來提問:可不可以將程序中,捕捉函數(shù)內(nèi)部的 while 替換為 if,即將代碼?while((waitpid(0, &status, WNOHANG) > 0)) 換為 if((waitpid(0, &status, WNOHANG) > 0))?為什么?
答案:不可以,修改下并運行:
子進(jìn)程的 ID:15384 子進(jìn)程的 ID:15385 子進(jìn)程的 ID:15386 子進(jìn)程的 ID:15388 父進(jìn)程的 ID:15383 子進(jìn)程的 ID:15390 子進(jìn)程的 ID:15393 子進(jìn)程的 ID:15387 子進(jìn)程的 ID:15392 子進(jìn)程的 ID:15389 子進(jìn)程的 ID:15391 子進(jìn)程正常退出,狀態(tài):0 父進(jìn)程的 ID:15383 子進(jìn)程正常退出,狀態(tài):0 父進(jìn)程的 ID:15383 子進(jìn)程正常退出,狀態(tài):0 父進(jìn)程的 ID:15383 父進(jìn)程的 ID:15383 父進(jìn)程的 ID:15383 父進(jìn)程的 ID:15383 父進(jìn)程的 ID:15383 父進(jìn)程的 ID:15383可以發(fā)現(xiàn),有 7 個子進(jìn)程的退出狀態(tài)父進(jìn)程沒有捕獲到,原因是 if 只執(zhí)行一次回收(因為到了那兒說明父進(jìn)程收到信號了,也就是說一定有子進(jìn)程死掉了。)但是若是某一個時刻有多個子進(jìn)程同時死了,那么依據(jù)信號不進(jìn)行排隊的原理,就只有其中一個信號被處理,其他的被忽略。但是 while 就不一樣了,就算同時來多個信號,但是 while 時循環(huán)執(zhí)行,雖然信號處理先后順序不一樣,但是每個信號都會被處理啊(非阻塞的 waitpid 函數(shù))。
所以啊,當(dāng)有多個子進(jìn)程時,回收的時候用循環(huán),不要用 if。
?
參考:https://blog.csdn.net/weixin_30752699/article/details/97366496
?
(SAW:Game Over!)
?
總結(jié)
以上是生活随笔為你收集整理的OS / Linux / SIGCHLD 信号的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: signal(SIGCHLD, SIG_
- 下一篇: OS / Linux / SIGKILL