通过wait函数或者waitpid函数可以清理僵尸进程,父进程可以通过两种方式等待子进程,一种是阻塞方式,另一种是非阻塞方式,而不管是那种方式,父进程都做不到完全不理会子进程而去完成自己的动作,即子进程不能达到异步等待的目的。
1、关于SIGCHLD信号
1、关于SIGCHLD信号
子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程就可以进行自己的动作而不必管理子进程,子进程只需要在退出时通知父进程,父进程在信号处理函数中调用wait函数来清理子进程即可。
我们可以自定义handler函数捕捉SIGCHLD信号并进行处理。
下面是一个信号捕捉的小程序:
在这个程序中,我们自定义了子进程在退出时打印信号编码,可以看到子进程退出时发送给父进程的是17号信号,即SIGCHLD
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<signal.h>
4 #include<stdlib.h>
5
6 void handler(int signo)
7 {
8 printf("sig:%d,id:%d\n",signo,getpid());
9 }
10
11 int main()
12 {
13 int i=0;
14 for(i=0;i<32;i++)
15 {
16 signal(i,handler);
17 }
18 pid_t id=fork();
19 if(id==0)
20 {
21 sleep(2);
22 printf("i am child");
23 exit(1);
24 }
25 else{
26 sleep(5);
27 printf("i am father");
28 }
29 return 0;
30 }
31
2、关于子进程的异步等待
父进程在等待时可以选择异步等待,即在等待的同时做自己的事情,是非阻塞等待
利用waitpid函数,将参数设置为WNOHANG,若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,即此时以非阻塞方式(轮询式访问的必要条件)等待子进程,并且返回0。
下面是一个例子:
1 #include<stdio.h>
2 #include<signal.h>
3 #include<stdlib.h>
4 #include<sys/types.h>
5 void handler(int signo)
6 {
7 pid_t id;
8 while(1)
9 {
10 switch(id==waitpid(-1,NULL,WNOHANG))
11 {
12 case 0:
13 case 1:
14 return;
15 default:
16 printf("wait success!%d\n",id);
17 break;
18 }
19 }
20 }
21 int main()
22 {
23 signal(SIGCHLD,handler);
24 pid_t id=fork();
25 if(id==0){//child
26 sleep(5);
27 printf("i am child:%d\n",getpid());
28 exit(1);
29 }
30 else
31 {
32 while(1){
33 printf("i am father, doing my thing!\n");
34 sleep(1);
35 }
36 }
37 }
从运行结果可以看出,子进程在sleep时父进程并没有堵塞等待,而是做自己的事情,知道子进程退出。