一文了解进程等待

文章介绍了进程等待的重要性,避免僵尸进程的产生以及回收资源。wait和waitpid是两个用于等待子进程退出的系统调用,wait是阻塞接口,等待任意子进程退出,而waitpid提供更多的灵活性,可以选择等待特定子进程并支持非阻塞模式。通过这两个函数,父进程可以获取子进程的退出状态,包括退出码和退出信号,从而判断子进程的退出情况。
摘要由CSDN通过智能技术生成

目录

前言:

进程等待的方法:

int wait(int *status)------阻塞接口 

int waitpid(pid_id,int *status,int option)

获取子进程status 

前言:

首先我们需要知道为什么要进行进程等待:

之前讲过,子进程退出,父进程如果不管不顾,就可能造成 僵尸进程 的问题,进而造成内存泄漏。
另外,进程一旦变成僵尸状态,那就刀枪不入, 杀人不眨眼 kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
最后,父进程派给子进程的任务完成的如何,我们需要知道。子进程运行完成,结果对还是不对,或者是否正常退出。
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

进程等待的方法:

操作系统总共给我们提供了两个接口:

在了解这两个接口之前,我们先来看看阻塞和非阻塞的区别:

阻塞:为了完成某个操作,发起调用,但是若不具备操作的完成条件,则调用一直等待。

非阻塞:为了完成某个操作,发起调用,但是若不具备操作的完成条件 ,立即报错返回。

int wait(int *status)------阻塞接口 

功能:等待任意一个子进程退出,若当前没有子进程退出,则一直等待

           成功则返回值大于0,是退出子进程的pid;若出错,则返回-1

参数:int *status---整形空间的地址;保存退出子进程的退出状态。 

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/wait.h>
  5 int g_val=0;
  6 int a=8;
  7 
  8 int main()
  9 {  pid_t id=fork();
 10     if(id<0){
 11         perror("fork");
 12         return 0;
 13     }
 14     else if(id==0){
 15         int cut=5;
 16         while(cut){
 17             printf("我是子进程,我还剩下%d秒\n",cut--);
 18             sleep(1);
 19         }
 20     }
 21     else
 22     {
 23 
 24         pid_t id=wait(NULL);
 25         if(id>0)
 26         {
 27             printf("获取成功,退出子进程的pid是%d\n",id);
 28         }
 29         else if(id=-1) {
 30             printf(" 等待失败\n");
 31         }
 32         while(1){
 33             printf("我是父进程,我在等待子进程退出!\n");
 34             sleep(1);
 35 
 36         }
 37         return 0;
 38     }
 39 }

这时我们可以看到,当子进程退出后,父进程读取了子进程的退出信息,子进程也就不会变成僵尸进程了。 由此得知我们可以通过wait()的方案解决回收子进程Z状态,让子进程进入X。

int waitpid(pid_id,int *status,int option)

功能:若pid参数设置为-1,则表示等待任意子进程退出,否则就是等待指定子进程退出

参数:

pid:-1等待任意子进程退出,大于0表示等待指定子进程

status:获取退出子进程的状态

option:0-默认阻塞操作;WNOHANG-非阻塞操作(没有子进程退出立即返回)

返回值:若处理了指定子进程的退出,则返回值大于0;若等于0则表示没有子进程退出;出错则返回值小于0;

waitpid(-1,NULL,0)等价于wait(NULL);

注意点:wait&waitpid获取的是已经退出的子进程状态

              >>调用的时候已经有退出的,则直接处理

              >>调用的时候已经有多个退出的,则只处理一个 

下面我们先看看阻塞操作:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/wait.h>
  5 int g_val=0;
  6 int a=8;
  7 
  8 int main()
  9 {  pid_t id=fork();
 10     if(id<0){
 11         perror("fork");
 12         return 0;
 13     }
 14     else if(id==0){
 15         int cut=5;
 16         while(cut){
 17             printf("我是子进程,我还剩下%d秒\n",cut--);
 18             sleep(1);
 19         }
 20     }
 21     else
 22     {
 23 
 24         pid_t id=waitpid(-1,NULL,0);
 25         if(id>0)
 26         {
 27             printf("获取成功,退出子进程的pid%d\n",id);
 28         }
 29         else if(id=-1) {
 30             printf(" 等待失败\n");
 31         }
 32         while(1){
 33             printf("我是父进程,我在等待子进程退出!\n");
 34             sleep(1);
 35 
 36         }
 37         return 0;
 38     }
 39 }

下面是非阻塞操作:

 1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/wait.h>
  5 int g_val=0;
  6 int a=8;
  7 
  8 int main()
  9 {  pid_t id=fork();
 10     if(id<0){
 11         perror("fork");
 12         return 0;
 13     }
 14     else if(id==0){
 15         int cut=5;
 16         while(cut){
 17             printf("我是子进程,我还剩下%d秒\n",cut--);
 18             sleep(1);
 19         }
 20     }
 21     else
 22     {
 23 
 24         pid_t id=waitpid(-1,NULL,WNOHANG);
 25         if(id>0)
 26         {
 27             printf("获取成功,退出子进程的pid是%d\n",id);
 28         }
 29         else if(id=-1) {
 30             printf(" 等待失败\n");
 31         }
 32         while(1){
 33             printf("我是父进程,我在等待子进程退出!\n");
 34             sleep(1);
 35 
 36         }
 37         return 0;
 38     }
 39 }

 

 我们会发现依然产生了僵尸进程。因为当我非阻塞操作的时候,当父进程发现子进程还没有退出,此时它就会去运行自己的代码,但当子进程推出之后,父进程依然再做自己的事情,那么就会忽略子进程的退出,所以为了让非阻塞操作也能完成等待任务,通常我们都要循环进行非阻塞操作。

 1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/wait.h>
  5 int g_val=0;
  6 int a=8;
  7 
  8 int main()
  9 {  pid_t id=fork();
 10     if(id<0){
 11         perror("fork");
 12         return 0;
 13     }
 14     else if(id==0){
 15         int cut=5;
 16         while(cut){
 17             printf("我是子进程,我还剩下%d秒\n",cut--);
 18             sleep(1);
 19         }
 20     }
 21     else
 22     {
 23         pid_t id;
 24         while((id=waitpid(-1,NULL,WNOHANG)==0))
 25                     {
 26                         printf("有子进程,但是还没退出!\n");
 27                         sleep(1);
 28                     }
 29         printf("子进程已经退出,退出子进程的pid是%d\n",id);
 30         while(1)
 31         {
 32             printf("我是父进程,我正在等待子进程退出!\n");
 33             sleep(1);
 34         }
 35         return 0;
 36     }
 37  }

 我们再看就没有僵尸进程了

获取子进程status 

wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
如果传递NULL,表示不关心子进程的退出状态信息。
否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

解释上图:

  • 在status的低16比特位当中,高8位表示进程的退出状态,即退出码。进程若是被信号所杀,则低7位表示终止信号,而第8位比特位是core dump标志。

我们通过一系列位操作,就可以根据status得到进程的退出码和退出信号。

exitCode = (status >> 8) & 0xFF; //退出码
exitSignal = status & 0x7F;      //退出信号

对于此,系统中提供了两个宏来获取退出码和推出信号。

  • WIFEXITED(status):用于查看进程是否是正常退出,本质是检查是否收到信号。
  • WEXITSTATUS(status):用于获取进程的退出码
exitNormal = WIFEXITED(status);//是否正常退出
exitCode = WEXITSTATUS(status);//获取退出码

需要注意的是,当一个进程非正常退出时,说明该进程是被信号所杀,那么该进程的退出码也就没有意义了。


  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/wait.h>
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id<0)
  9     {
 10         perror("fork");
 11         return 0;
 12     }else if(id==0)
 13     {
 14         sleep(5);
 15         exit(99);
 16     }else
 17     {
 18         int status;
 19         pid_t ret=waitpid(-1,&status,0);
 20         if(ret<0)
 21         {
 22             perror("waitpid");
 23         }
 24         else if(ret>0)
 25         {
 26             printf("子进程已经退出,退出子进程的pid是%d,退出码是%d,退出信号是%d\n",ret,WEXITSTATUS(status),WIFEXITED(status));
 27         }else
 28         {
 29             printf("当前没有子进程退出\n");
 30         }
 31         while(1)
 32         {
 33             printf("我是父进程,我在等待\n");
 34             sleep(1);
 35         }
 36     }
 37     return 0;
 38 }

问:一个进程退出的时候,父进程会拿到退出码和退出信号,那到底先看谁呢?

  • 一旦进程出现异常,只关心退出信号,退出码没有任何意义。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值