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信号捕捉函数,等待成功后,若当前暂时再没有了退出的子进程,其则不阻塞等待而去执行自己的工作。
如下结果: