僵尸进程:子进程结束运行后,父进程读取退出状态前,我们称该子进程处于僵尸态。
父进程结束或者异常终止,而子进程继续运行,在父进程退出之后,子进程退出之前,该子进程处于僵尸态。
如果父进程没有正确处理子进程的返回信息,子进程都将停留在讲师态,并占据着内核资源。这是绝对不容许的,毕竟内核资源有限。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
从结果可以看到,子进程退出后,父进程立即结束了子进程的僵尸态,子进程结束前,父进程一直在运行,没有阻塞等待子进程的退出,这种方式效率高。