多进程---为子进程收尸

僵尸进程

僵尸进程:子进程结束运行后,父进程读取退出状态前,我们称该子进程处于僵尸态。
父进程结束或者异常终止,而子进程继续运行,在父进程退出之后,子进程退出之前,该子进程处于僵尸态。

waitpid

如果父进程没有正确处理子进程的返回信息,子进程都将停留在讲师态,并占据着内核资源。这是绝对不容许的,毕竟内核资源有限。waitpid在父进程中调用,以等待子进程的结束,并获取子进程的返回信息,从而避免僵尸进程的产生,或者使子进程的僵尸态立即结束:
#include
#include

pid_t waitpid(pid_t pid, int * stat_loc, int options);
功能:等待子进程的退出
参数:pid:
pid > 0 时只等待相应pid的子进程退出,对其他子进程是否退出不予处理
pid = -1时等待任意子程序退出,同wait
pid = 0 时调用ID(即使用waitpid这个函数的进程的ID)等于某个进程组的组ID这时这个进程组中任意进程退出,就将被接受
pid < -1 时等待其组ID等于pid的绝对值得任一子程
options:常用值WNOHANG:使调用 进程处于非阻塞态,当子进程一时间不退出时,父进程也不会阻塞
返回值:
正常:结束返回子进程号,使用选项WNOHANG且没有子进程结束时返回0;
出错返回-1;

一种好的处理僵尸进程的方式

要在事件已经发生的情况下执行非阻塞调用才能提高程序的效率。对waitpid函数而言,我们最后在某个子进程退出之后再代用它。当一个进程结束时,它将给父进程发送一个SIGCHLD信号,因为,我们可以在父进程中捕获SIGCHLD信号,并在信号处理函数中调用waitpid函数以“彻底结束”一个子进程。测试代码如下:

1 #include <stdio.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <signal.h>
5 #include <sys/wait.h>
6 
7 
8 void  child_process(int array[],int len)
9 {
10    int p = 0;
11     for(; p<3; p++)
12     {
13         printf("我是child, %d, %d\n",array[0],array[1]);
14         array[len-1] += 1;
15         sleep(1);
16     }
17     exit(0);
18 }
19  //SIGCHLD信号处理函数
20 void proc_child_exit(int sig)
21 {
22     if ( sig == SIGCHLD )
23     {
24         while ( waitpid(-1, NULL, WNOHANG) > 0)
25         {
26             printf("为子进程收尸\n");
27         }
28     }
29 }
30
31 
32 void parent_process(int array[], int len)
33 {
34     int t = 0;
35     for (t; t<7; t++)
36     {
37         printf("我是parent, %d, %d\n",array[0],array[1]);
38         array[len-1] += 1;
39         sleep(1);
40     }
41 }
42 
43 int main()
44 {
45     int array[]={3,4};
46     pid_t child_p;
47     struct sigaction  act;
48 
49     sigemptyset(&act.sa_mask); //清空此信号集
50     act.sa_handler = proc_child_exit; 
51     act.sa_flags = 0;
52 
53     sigaction(SIGCHLD, &act, NULL);//注册SIGCHLD信号
54 
55     child_p = fork();
56     if ( child_p == 0 )
57     {
58        child_process(array,2);
59     }
60 
61     parent_process(array,2);
62 
63     return 1;
64 }

执行结果如下:
我是parent, 3, 4
我是child, 3, 4
我是parent, 3, 5
我是child, 3, 5
我是parent, 3, 6
我是child, 3, 6
我是parent, 3, 7
为子进程收尸
我是parent, 3, 8
我是parent, 3, 9
我是parent, 3, 10

从结果可以看到,子进程退出后,父进程立即结束了子进程的僵尸态,子进程结束前,父进程一直在运行,没有阻塞等待子进程的退出,这种方式效率高。

你可能感兴趣的:(进程通信)