SIGCHLD:子进程在终止退出时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略。
验证如下:创建一个子进程,自定义信号SIGCHLD的捕捉函数,若子进程退出并调用了此信号捕捉函数,则验证成功。
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> void myhander(int sig) { printf("father get child sig,child exit, sig##%d\n",sig); } int main() { signal(SIGCHLD,myhander); pid_t id=fork(); if(id==0) //child { printf("child is doing something:child pid##%d\n",getpid()); sleep(1); exit(1); //子进程退出 } //验证是否发信号SIGCHLD,执行myhander函数 pid_t ret=waitpid(id,NULL,0); //阻塞等待子进程 if(ret>0) { printf("wait success!!!child pid##%d\n",ret); } return 0; }结果如下:验证成功
子进程异步等待方式:
用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得不时地轮询一 下,程序实现复杂。
所以由上可知父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会发信号通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
代码如下:
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> void myhander(int sig) //每个子进程退出发送信号进入此函数 { printf("father get child sig,child exit: sig##%d\n",sig); pid_t id; while((id=waitpid(-1,NULL,WNOHANG))>0) //父进程非阻塞等待当前任意退出的子进程 { printf("wait success!!! child pid##%d\n",id); } } int main() { signal(SIGCHLD,myhander); //注册信号处理函数 pid_t id1=fork(); //创建子进程1 if(id1==0) //child { printf("child is doing something:child1 pid##%d\n",getpid()); exit(1); //运行完退出 } pid_t id2=fork(); //创建子进程2 if(id2==0) //child { printf("child is doing something:child2 pid##%d\n",getpid()); sleep(2); exit(-1); //2s后异常退出 } while(1) //父进程每1s打印一次 { printf("father is doing something!!!\n"); sleep(1); } return 0; }以上代码中创建两个子进程第一个直接退出,第二个等待2S退出,则在它们各自退出时间发送信号给父进程,父进程则在各自退出时间执行SIGCHLD信号捕捉函数,等待成功后,若当前暂时再没有了退出的子进程,其则不阻塞等待而去执行自己的工作。
如下结果: