对于学习进程等待,先弄清楚下面几个问题:
什么是进程等待?
进程等待其实就是通过系统调用wait/waitpid对子进程的执行状态(执行过程中发生的异常;子进程执行结束返回的退出码)进行检测与回收子进程。
为什么要进程等待?
1、当在父进程中fork创建了一个子进程,子进程执行完毕先退出后(此时子进程的状态就是僵尸状态Z)父进程如果对其不管不顾,就无法释放创建的子进程导致内存泄漏,指令kill -9 PID只会让子进程提前退出。
2.父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
怎么进行进程等待?
父进程通过系统调用wait/waitpid进行对僵尸进程的回收。
wait
返回值: 成功返回被等待进程 pid ,失败返回 -1 。
参数: 输出型参数,获取子进程退出状态 , 不关心则可以设置成为 NULL
注意:如果子进程一直不退出,父进程默认在调用wait等待子进程的时候,此时父进程处于阻塞状态。
父进程等待单个子进程:
testwait.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 int main()
7 {
8 pid_t id = fork();
9 if(0 == id)
10 {
11 int cnt = 6;
12 while(cnt)
13 {
14 printf("i am child pid:%d cnt:%d\n", getpid(), cnt);
15 cnt--;
16 sleep(1);
17 }
18 }
19 else if(id > 0)
20 {
21 int cnt = 10;
22 while(cnt)
23 {
24 printf("i am parent pid:%d cnt:%d\n", getpid(), cnt);
25 cnt--;
26 sleep(1);
27 }
28 pid_t tmp = wait(NULL);
29 if(tmp > 0)
30 printf("wait success pid:%d\n", id);
31 else
32 printf("wait fail\n");
33 sleep(10);
34 }
35 return 0;
36 }
检测结果:
上述结果证明父进程成功等待了退出的子进程。
父进程等待多个子进程:
testwait.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6
7 #define NUM 5
8
9 void runChild()
10 {
11 int cnt =5;
12 while(cnt)
13 {
14 printf("i am child pid:%d ppid:%d\n", getpid(), getppid());
15 sleep(1);
16 cnt--;
17 }
18 }
19 int main()
20 {
21 for(int j= 0;j<NUM;j++)
22 {
23 pid_t tmp = fork();
24 if(0 == tmp)
25 {
26 runChild();
27 exit(1);
28 }
29 printf("i am parent pid:%d\n", getpid());
30 }
31 sleep(10);
32 for(int i=0;i<NUM;i++)
33 {
34 pid_t ret = wait(NULL);
35 if(ret>0)
36 printf("wait success\n");
37 else
38 printf("wait fail\n");
39 }
40 sleep(10);
41 return 0;
42 }
根据上面试验结果可以看出父进程成功等待了退出的子进程。
waitpid
返回值:当正常返回的时候 waitpid 返回收集到的子进程的进程pid ;如果设置了选项 WNOHANG, 而调用中 waitpid 发现没有已退出的子进程可收集 , 则返回 0 ;如果调用中出错 , 则返回 -1, 这时 errno 会被设置成相应的值以指示错误所在;
参数:
pid :pid=-1, 等待任一个子进程。与 wait 等效。pid>0, 等待其进程pid 与 pid 相等的子进程。
status:WIFEXITED(status) : 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出(即子进程没有发生异常终止退出))WEXITSTATUS(status) : 若 WIFEXITED 非零,提取子进程退出码。(查看进程的退出码)这里介绍一下参数status :
status是输出型参数:就是通过传入我们自己定义的整型变量的地址status可以得到操作系统内核的信息(即得到子进程执行情况的信息)。
status一共是32bit位,最后7位储存子进程异常终止的信息;次8位存储子进程退出状态(退出码)。satus在写代码时是需要我们自己定义的变量
options:WNOHANG: 若 pid 指定的子进程没有结束,则 waitpid() 函数返回 0 ,不予以等待。若正常结束,则返回该子进程的pid 。非阻塞轮询:此时父进程的状态就不是阻塞状态了,父进程可以通过while循环对子进程进行轮询,在此轮询子进程期间父进程可以做它自己的任务。子进程退出则父进程就等待子进程,进而回收子进程。