LInux:进程等待之wait() & waitpid()

进程等待

之前说,子进程退出,父进程如果不管不顾,就可能造成“僵尸进程”的问题,进而造成内存泄露,进而,进程一旦变成僵尸状态,杀人不眨眼的”kill -9”也无能为力,因为谁也没有办法杀死一个已经死去的进程,最后,父进程派给子进程的任务完成的如何,我们需要知道,如子进程运行完成,结果是还是不对,或者是否正常退出,我们需要知道

父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

进程等待方法

wait()


头文件:#include<sys/wait.h>
        #include<sys/type.h>
原型
pid_t wait(int *status)
返回值:
    成功:返回被等待进程(子进程)pid
    失败:返回-1
参数:输出型参数,获取子进程退出状态,不关心则可以设置为NULL

waitpid()

头文件: #include<sys/type.h>
        #include<sys/wait.h>
返回值:
   (1)当正常返回的时候waitpid返回收集到的子进程的进程ID

   (2)如果设置了选项WNOHANG,而调用中waitpid发现已经没
      有已经可以退出的子进程可收集,则返回0

   (3)如果调用中出错,则返回-1,这时errno会被设置成相应的
      值以指示错误所在

原型

pid_t waitpid(pid_t pid,int *status,int options)

参数说明:

1.pid
  pid=-1,等待任一个子进程,与wait等效
  pid>0,等待其进程ID与pid相等的子进程
2.status
   WIFEXITED(status):    若为正常终止子进程返回的状态,则为
                         真(此参数是查看进程是否是正常退出)

   WEXITSTATUS(status):  若WEXITSTATUS非零,提取子进程退
                         出码(查看进程的退出码)
3.options
     WNOHANG:若pid指定的子进程没有结束,则waitpid()函数
              返回0,不予以等待,若正常结束,则返回该子进程的ID

(1)如果子进程已经退出,调用wait/waitpid会立即返回,并且释放资源,获得子进程退出信息
(2)如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
(3)如果不存在该子进程,则立即出错返回
(4)子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)

获取子进程status

wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充
如果传递NULL,表示不关心子进程的退出状态信息,
否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程

status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位)

这里写图片描述

正常终止

status & 0x7f,   如果是0的话,那就表示正常退出
0xff是0111111,status 按位与0x7f,表示取出status的低7位

当正常终止的时候,status高8位就是子进程的退出码

status & 0xff,就是取出status的高8位

异常终止

status & 0x7f,   不为0的话,那就表示异常退出

判断子进程正常/异常退出的时候:
status & 0x7f(status按位与0x7f)的时候,按位与7位就好,如果按位与的结果是0,那就表示子进程正常退出,按位与的结果不是0,那就表明子进程异常退出

阻塞式等待&非阻塞式等待


1.阻塞式等待
   子进程先执行,而且父进程会等待子进程执行结束,再去执行自己
2.非阻塞式等待
   子进程和父进程谁先执行不确定,父进程如果先执行的话,父进程会一边等待
   子进程而另一边又做自己的事情,即就是等待子进程和执行自己的事情是同步
   进行的

示例

进程的阻塞等待方式

wait()

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/wait.h>
int main()
{
    pid_t pid;
    if((pid=fork())==-1)
    {
        perror("fork()");
        exit(1);
    }
    if(pid==0)//child
    {
        sleep(30);
        exit(10);
    }
    if(pid>0)
    {
        int status;
        int ret=wait(&status);
        if(ret>0&&((status&0x7f)==0))
        {
            printf("child exit code:%d\n",(status>>8)&0xff);
        }
        //status>>8表示把status的低8位右移出去
        //(status>>8)&0xff表示把status的低8位右移出去(系统会给status会补够32位),然后与0xff按位与,得到status的低8位,此结果就是子进程的退出码
        else if(ret>0)
        {
            //异常退出
            printf("sig code: %d\n",status&0x7f);
        }
    }
    return 0;
}

运行结果
这里写图片描述
等待30s之后
这里写图片描述
此运行结果是子进程正常退出的场景

在另一个终端把子进程kill掉
这里写图片描述

ps:   ps -ef | grep a.out  是查看进程的pid

kill -9+pid 是杀死进程ID为pid的进程
例图中 kill -9 2612 就是杀死进程为2612的进程

这里写图片描述
进程退出信号是:9号信号

waitpid()

代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>//waitpid()的头文件
int main()
{
 pid_t pid=fork();
 if(pid<0)
 {
  perror("fork");
  exit(1);
 }
 if(pid==0)
 {
  printf("child is run,child pid is :%d\n",getpid());//getpid()得到的是当前进程的pid
  sleep(5);
  exit(10);
 }
 if(pid>0)
 {
  int status=0;
  pid_t ret=waitpid(-1,&status,0);//阻塞式等待,等待5秒
  printf("this is for test wait.\n");
  if(WIFEXITED(status)&&(ret==pid))
  {
   printf("child is 5s succes.child exit code is :%d\n",WEXITSTATUS(status));
  }
  else if(ret>0)
  {
   printf("wait child failed.\n");
   exit(1);
  }
 }
 return 0;
}

运行结果:
这里写图片描述
等待5秒过后
这里写图片描述

阻塞式等待,父进程等待子进程执行,然后在执行自己

进程的非阻塞等待方式

waitpid()

代码:

include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
 pid_t pid=fork();
 if(pid<0)
 {
  perror("fork");
  exit(1);
 }
 if(pid==0)
 {
  printf("child is run,child pid is :%d\n",getpid());
  sleep(5);
  printf("child is run.\n");
  exit(10);
 }
 if(pid>0)
 {
  int status=0;
  pid_t ret=0;//记得需要声明ret
  do
  {
   ret=waitpid(-1,&status,WNOHANG);//非阻塞式等待
   if(ret==0)
   {
    printf("child is running,\n");
   }
   sleep(1);
  }while(ret == 0);//ret!=0表示子进程结束
  if(WIFEXITED(status)&&(ret==pid))
  {
   printf("wait child 5s success,child exit code is:%d\n",WEXITSTATUS(status));
  }
  else
  {
   printf("wait child failed.\n");
   exit(1);
  }
 }
 return 0;
}

运行结果:
这里写图片描述

非阻塞式等待,就是谁先执行不一定,在此代码中,是父进程先执行的,然后让父进程睡眠1s,从而让子进程执行,子进程执行到sleep(5)时,此时又去执行父进程,但是子进程还没有执行结束,故一直执行while循环,5s过后,又再次遇到sleep(1),又去执行子进程,这时子进程就会结束,父进程继续完成自己的工作

WIFEXITED(status)为真---->进程正常退出
若WEXITSTATUS(status)>0---->WEXITSTATUS(status)表示子进程的退出码

这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值