回收子进程

1.一些概念:

孤儿进程

  父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为进程领养孤儿进程。

僵尸进程

  进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。

  僵尸进程不能使用kill命令清除,因为kill命令只是用来终止进程的,而僵尸进程已经终止了。

 

2.wait函数

  一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息,如果是正常终止则保存着退出状态;如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在Shell中用特殊变量$?查看,当它终止时Shell调用wait或waitpid得到它的退出状态,同时清除这个进程。

  父进程调用wait函数可以回收子进程终止信息。该函数有三个作用:

  ①阻塞等待子进程退出

  ②回收子进程残留资源

  ③获取子进程结束状态(退出原因);

 

  pid_t wait(int *status);成功:清除掉子进程ID;失败:-1(没有子进程信息)

  当进程终止时,操作系统的隐式回收机制会:1.关闭所有文件描述符;2.释放用户空间分配的内存。内核的PCB仍存在,其中保存该进程的退出状态。(正常终止 -> 退出值,异常终止 -> 终止信号)

  可使用wait函数传出参数status来保存进程的退出状态,借助宏函数来进一步判断终止进程的具体原因,宏函数可分如下三组:

  1.WIFEXITED(status)为非0 -> 进程正常结束

   WEXITSTATUS(status)如上宏为真,使用此宏 -> 获取进程退出状态(exit参数或return返回值)

  2.WIFSIGNALED(status)为非0 -> 进程异常结束

   WTERMSIG(status)如上宏为真,使用此宏 -> 获取使进程终止的那个信号的编号

  3.WIFSTOPPED(status)为非0 -> 进程处于暂停状态

   WSTOPSIG(status)如上宏为真,使用此宏 -> 获取使进程暂停的那个信号的编号

   WIFCONTINUE(status)为真 -> 进程暂停后已经进行运行

例:子进程正常退出,调用算上述宏函数

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/wait.h>
 7 
 8 int main()
 9 {
10         int pid = fork();
11         int status;
12         int wpid;
13         if(pid == 0){
14                 sleep(3);
15                 printf("----------------child process is over--------------\n");
16                 exit(100);
17         }else if(pid > 0){
18                 wpid = wait(&status);
19                 printf("wpid = %d\n",wpid);
20                 if(WIFEXITED(status)){
21                         printf("子进程正常退出,退出值为:%d\n",WEXITSTATUS(status));
22                 }
23         }
24         return 0;
25 }

运行结果:

 

3.waitpid函数

作用与wait相同,但waitpid可指定pid进程清理,可以不阻塞。

pid_t waitpid(pid_t pid,int *status,int options);成功:返回清理掉的子进程的id;失败:-1(无子进程)

特殊参数和返回情况:

参数pid:

  >0 回收指定id的子进程

  -1  回收任意子进程(相当于wait)

  0   回收和当前调用waitpid一个组的所有子进程

  <-1 回收指定进程组内的任意子进程

参数options:

  0         阻塞,相当于wait

  WNOHANG 非阻塞回收(轮询)

返回0:options传WNOHANG,且子进程正在运行

注意:一次wait或waitpid调用只能清理一个子进程;清理多个子进程应使用循环。 

根据子进程id进行回收

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/wait.h>
 7 
 8 int main()
 9 {
10         int status;
11         int child_pid;
12         pid_t p,q;
13 
14         int i;
15         int n = 5;      //创建5个子进程
16         for(i=0;i<n;i++){
17                 p = fork();
18                 if(p == 0){
19                         break;  //子进程创建后退出循环
20                 }else if(i == 3){
21                         q = p;  //取出第4个子进程的id
22                 }
23         }
24 
25         if(i == n){
26                 sleep(n);
27                 child_pid = waitpid(q,&status,0);       //根据子进程id进行回收
28                 while(1);
29         }else if(i<n){
30                 sleep(i);
31                 printf("I'm %d child,pid = %d,ppid = %d\n",i+1,getpid(),getppid());
32         }
33 
34         return 0;
35 }

循环回收子进程

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/wait.h>
 7 
 8 int main()
 9 {
10         int status;
11         int child_pid;
12         pid_t p,q;
13 
14         int i;
15         int n = 5;      //创建5个子进程
16         for(i=0;i<n;i++){
17                 p = fork();
18                 if(p == 0){
19                         break;  //子进程创建后退出循环
20                 }else if(i == 3){
21                         q = p;  //取出第4个子进程的id
22                 }
23         }
24 
25         if(i == n){
26                 sleep(n);
27                 while(waitpid(-1,&status,0)!=-1){       //循环回收子进程
28                 }
29                 while(1){}      //让父进程不退出
30         }else if(i<n){
31                 sleep(i);
32                 printf("I'm %d child,pid = %d,ppid = %d\n",i+1,getpid(),getppid());
33         }
34 
35         return 0;
36 }
37 ~                    

非阻塞(轮询)方式回收子进程

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/wait.h>
 7 
 8 int main()
 9 {
10         int status;
11         int child_pid;
12         pid_t p,q;
13 
14         int i;
15         int n = 5;      //创建5个子进程
16         for(i=0;i<n;i++){
17                 p = fork();
18                 if(p == 0){
19                         break;  //子进程创建后退出循环
20                 }else if(i == 3){
21                         q = p;  //取出第4个子进程的id
22                 }
23         }
24 
25         if(i == n){
26         //      sleep(n);
27                 do{
28                         child_pid = waitpid(-1,&status,WNOHANG);
29                         if(child_pid > 0){      //n>0代表回收成功
30                                 n--;
31                         }
32                 }while(n>0);
33         }else if(i<n){
34                 sleep(i);
35                 printf("I'm %d child,pid = %d,ppid = %d\n",i+1,getpid(),getppid());
36         }
37 
38         return 0;
39 }
40 ~                          

 

posted @ 2021-02-15 21:07  さくらむすび  阅读(96)  评论(0)    收藏  举报