子进程的异步等待方式

来源:互联网 发布:音频矩阵 线序 编辑:程序博客网 时间:2024/06/06 06:51

        我们知道可以用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方

式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂。

        其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只专心处理自己的工作,不

必关心子进程,子进程终止会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。接下来我们来验证子进程终止时会给父进程发SIGCHLN信号,代码如下:

  1 #include<stdio.h>  2 #include<stdlib.h>  3 #include<signal.h>  4 #include<sys/types.h>  5 void handler(int sig)  6 {  7     printf("sig is %d,pid is %d\n",sig,getpid());  8 }  9 int main() 10 { 11     signal(SIGCHLD,handler); 12     int id=fork(); 13     if(id<0) 14     { 15         perror("fork"); 16         exit(-1); 17     } 18     else if(id==0) 19     { 20         sleep(3); 21         printf("i am child,my pid %d\n",getpid()); 22         exit(2); 23     } 24     else 25     { 26         while(1) 27         { 28             printf("i am parent,my pid is %d\n",getpid()); 29             sleep(1); 30         } 31     } 32     sleep(1); 33 }

运行结果如下:


    子进程退出后,向父进程发送17SIGCHLD父进程对信号进行捕获,打印信号编号以及父进程的pid,等待成功后,返回子进程的pid。下面我们来验证父进程等待子进程,

子进程调用exit(2)终止,父进程自定义SIGCHLD信号处理函数,在其中调用wait获取紫禁城的退出状态并打印。

  1 #include<stdio.h>  2 #include<stdlib.h>  3 #include<signal.h>  4 #include<unistd.h>  5 #include<sys/wait.h>  6 #include<sys/types.h>  7 void handler(int sig)  8 {  9     do 10     { 11         pid_t ret=waitpid(-1,NULL,0); 12         if(ret>0) 13         { 14             printf("wait success:%d\n",ret); 15         } 16         else 17         { 18             printf("wait failed\n"); 19             break; 20         } 21     } 22     while(1); 23 } 24 int main() 25 { 26     signal(SIGCHLD,handler); 27     int id=fork(); 28     if(id<0) 29     { 30         perror("fork"); 31         exit(-1); 32     } 33     else if(id==0) 34     { 35         sleep(3); 36         printf("i am child,my pid %d\n",getpid()); 37         exit(2); 38     } 39     else 40     { 41         while(1) 42         { 43             printf("do father thing!\n"); 44             sleep(1); 45         } 46     } 47     return 0; 48 }

       运行结果如下: 


        由于UNIX的历史原因,要想不产生僵尸进程还有另一种方法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,

不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户sigaction函数自定义的忽略通常没有区别,但这是一个特例,此方法对于Linux可用,但不保证在UNIX系统

上都可用。