前言:回收子进程之前用了wait()和非阻塞模型,今天学了信号以后可以使回收机制更上一层楼,通过信号函数,父进程只需要做自己的事情,接收到信号后就触发信号函数。
信号处理函数可能会出现的bug:
1.受到停止信号也会触发SIGCHLD信号,使wait阻塞;
2.停止后继续也会触发信号,导致父进程阻塞;
3.调用sigaction(),人为发送一个SIGCHLD信号也会使父进程阻塞;
4.多个进程同时结束,可能造成回收不完全,产生僵尸进程(同中信号不排队);
解决方案的终极代码:
//异步回收子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#define NR 40
/*
* bugs:如果多个进程同时结束 可能造成回收不完全 产生僵尸进程 (同种信号不排队)
* 循环方式waitpid解决以上bugs
*/
void waitChild(int signo)
{
pid_t pid;
printf("a sig recv:%d
",signo);
if(signo!=SIGCHLD) return;
while(1) //保证触发一次信号,回收所有结束的子进程
{
pid=waitpid(-1,NULL,WNOHANG|WUNTRACED);//保证非阻塞,以及停止不触发信号
printf("wait child:%d
",pid);
if(pid==0||pid==-1)
break;
}
}
int main(void)
{
pid_t pid;
#if 0
//子进程结束或停止 或者从停止到继续 发生SIGCHLD信号
if(signal(SIGCHLD,waitChild)==SIG_ERR)
{
perror("signal");
return 2;
}
#else
struct sigaction ac={.sa_handler=waitChild};//处理函数
sigemptyset(&ac.sa_mask);//不期望屏蔽其它信号
ac.sa_flags=SA_NOCLDSTOP;//进程停止时不发生SIGCHLD信号
sigaction(SIGCHLD,&ac,NULL);
#endif //
int i;
for(i=0;i<NR;i++)
{
pid=fork();
if(pid==-1) return 1;//error
else if(pid==0)//child
{
printf("%dth child <%d> start work.
",i,getpid());
sleep(3);
printf("%dth child <%d> end work.
",i,getpid());
exit(0);
}
}
//parent
while(1)
{
getchar();
printf("parent working....
");
}
return 0;
}