SIGCHLD的產生條件
子進程終止時
子進程接收到SIGSTOP信號停止時
子進程處在停止態,接受到SIGCONT后喚醒時
?
借助SIGCHLD信號回收子進程
?
子進程結束運行,其父進程會收到SIGCHLD信號。該信號的默認處理動作是忽略。可以捕捉該信號,在捕捉函數中完成子進程狀態的回收。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h>void sys_err(char *str) {perror(str);exit(1); } void do_sig_child(int signo) {int status; pid_t pid;while ((pid = waitpid(0, &status, WNOHANG)) > 0) {if (WIFEXITED(status))printf("child %d exit %d\n", pid, WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("child %d cancel signal %d\n", pid, WTERMSIG(status));} } int main(void) {pid_t pid; int i;for (i = 0; i < 10; i++) {if ((pid = fork()) == 0)break;else if (pid < 0)sys_err("fork");}if (pid == 0) { int n = 1;while (n--) {printf("child ID %d\n", getpid());sleep(1);}return i+1;} else if (pid > 0) {
//這里還應對SIGCHLD進行阻塞 防止父進程SIGCHLD還未注冊完成子進程就已經死亡struct sigaction act;act.sa_handler = do_sig_child;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, NULL);//解除阻塞while (1) {printf("Parent ID %d\n", getpid());sleep(1);}}return 0; }
?
上述代碼若將do_sig_child(),SIGCHLD信號處理函數改為:
void do_sig_child(int signo) {int status; pid_t pid;if((pid = waitpid(0, &status, WNOHANG)) > 0) { //將while改為ifif (WIFEXITED(status))printf("child %d exit %d\n", pid, WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("child %d cancel signal %d\n", pid, WTERMSIG(status));} }
此寫法會導致子進程回收不完全,原因:在執行信號處理函數時,多個子進程同時死亡,產生多個SIGCHLD信號。但由于函數正在執行故屏蔽SIGCHLD,但執行完成后未決信號集中只記錄一次SIGCHLD信號,故回收一次。子進程回收不完全。
?