Linux的进程等待

Linux的进程等待

在学习进程等待之前,我们要弄清楚,两个问题,一个是为什么要等待,还有一个是怎么等待?

首先:为什么要进程等待

进程终止或者退出的时候,进程就会关闭所有文件描述符,然后释放在用户空间的分配的内存,但是进程的PCB会暂时保留,因为PCB中还保存有进程的退出状态,如果进程是正常退出,那么退出状态就是进程的退出码,如果是异常退出,那进程的退出状态就是导致进程退出的信号,因为父进程必须要回收子进程,如果父进程在子进程之前退出,那么子进程就成了孤儿进程,所以父进程要拿到子进程的退出码,然后释放子进程。(来一点专业的描述:当一个进程终止的时候,内核会向其父进程发送信号,通知父进程要等待子进程,父进程调用wait)。

再者怎么进程等待?

在此之前,我们先总结一下进程退出的状态:①代码运行结束,结果正确,退出码为正常退出路径的退出码

②代码运行结束,结果错误,退出码为非正常退出路径的退出码

③代码没有运行结束,原因是收到某种退出信号

现在我们就要介绍两个系统调用函数:    wait   和waitpid

一、wait系统调用:pid_t wait (int* status)

参数:status, 是一个输出型参数,指向的空间存放着一个int类型的数字。高八位是程序的退出码,低七位是接收   到的信号(如果程序有接收到信号)

 如果程序是代码跑完,正常结束,那么status里面的高八位存着的就是程序的退出码,低八位就是0,   也就是什么信号都没有接收到。

 如果程序是异常终止,那么存着程序退出码的高八位就是0,第七位存放着接收到的信号

   如果不关心,那么也可以传NULL进去。

返回值:返回值>0,那么返回的就是等待进程的pid,这时候,我们就可以使用刚才的输出型参数status来查看进程的退出状态。

      返回值 == -1 ,那么调用失败,可能是因为没有子进程

wait的等待方式,是阻塞型等待,也就是说,只有等到有子进程给他返回退出状态的时候,他才会继续,如果没有子进程给他返回退出状态,那么父进程就会一直停止,处于等待的状态,如果有多个子进程,那么就会接收最先返回退出状态的子进程

二、waitpid系统调用:pid_t waitpid(pid_t pid,int* status,int options)

参数解析:pid:要等待子进程的pid,(这也是和wait的区别之一),如果输入:2554,那么就会等待pid为2554的进程返回的状态,

Tip:如果pid传进去的是-1,那么就表示等待任意一个进程的结束。

  status :和wait的statu是同样的,可以参考wait的status。

  options: options设置成1,那么就是阻塞式等待,和wait的效果一样。

   options设置成WNOHANG:那就是非阻塞式等待。当发现等待的进程没有退出,就返回0。

返回值:返回值>0,等待成功,返回的是等待进程的pid

       返回值==0, 等待的进程没有返回退出状态,也就是等待的那个进程没有退出

       返回值<0,调用失败

现在我们给出wait调用的代码:

该例子中,我们让子进程sleep 5s,并且返回一个比较明显的返回值,123,父进程调用wait,之后接收到子进程的返回状态,并把相关信息打印出来

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
int main(){
    pid_t id = fork();
    if(id == 0){
         printf("i am a child, pid:%d,ppid:%d \n",getpid(),getppid());
         sleep(5);
         exit(123);
     }
     else if(id > 0){
         printf("i am father,pid:%d,ppid:%d\n",getpid(),getppid());
         int status = 0;
         int  ret = wait(&status);
         if(ret>0){
             printf("wait success! ret:%d,exitcode:%d,sign:%d\n",ret,(status>>8)&0xff,status&0xff);
         }
     }
     else {
         perror("wait");
     }
     return 0;
 }
wait的调用结果:


在打印   “wait success! ret:2623,exitcode:123,sign:0”   这句话之前,停顿了5s,此时父进程就是在等待子进程给他返回退出码。

再看看waitpid的调用代码:

这个例子中,我们让子进程sleep 5s,标记一个明显的退出码123,此时调用waitpid,当子进程sleep的时候,父进程读到的是一个0的返回值,就会进入相应的循环分支

 #include<stdio.h>
 #include<stdlib.h>
 #include<sys/types.h>
 #include<sys/wait.h>
 int main(){
     pid_t id = fork();
     if(id == 0){
         printf("i am child,pid:%d,ppid:%d\n",getpid(),getppid());
         sleep(5);
         exit(123);
     }
     else if(id<0){
         perror("wait");
     }
     else{
         printf("i am father,pid:%d,ppid:%d\n",getpid(),getppid());
         int status = 0;
         do{
             int ret = waitpid(id,&status,WNOHANG);
             if(ret>0){
                 printf("wait success!id = %d,exitcode = %d,sign = %d \n",ret,(status>>8)&0xff,status&0xff);
                 break;
             }
             else if(ret == 0){
                 printf("father do other thing \n");
                 sleep(2);
             }
             else{
                 perror("wait");
                 break;
             }
         }while(1);
     }
     return 0;
 }
waitpid的运行结果:

打印 “father do other thing”,就说明进入了ret == 0的分支,

在打印 “father do other thing”之后,就会sleep 2s,再去打印下一句。



Tip:限于编者水平,文章难免有缺漏之处,欢迎大家指出。

如需转载,请注明出处!



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值