[linux]进程控制——进程等待

一、概念

进程等待,就是通过wait/waitpid的方式,让父进程(一般)对子进程进行资源回收的等待过程。

二、原因

(1)

当一个进程在退出的时候,如果不回收,就会变成僵尸状态,它让父进程等待之后,将僵尸状态进行回收。

僵尸就是进程或者子进程对应的代码和数据已经被释放,但是它的PCB以及它进程退出的相关数据依旧被维护,需要让父进程得知它的退出结果。

总结:

解决子进程僵尸问题带来的内存泄漏问题(是必须的)

(2)

父进程创建子进程,是为了让子进程帮助父进程完成父进程分配给子进程的任务。

所以,父进程需要知道子进程任务的完成情况。

总结:

需要通过进程等待的方式,获取子进程退出的信息。(不是必须的,但是系统需要提供这样的基础功能(可以不用,但不能没有))

三、如何实现进程等待

1、wait

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);

返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

演示:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(0);
  }
  else 
  {
    sleep(10);
    pid_t rid = wait(NULL);
    if(rid == id)
    {
      printf("wait sucess, pid:%d\n",getpid());
    }
  }



  return 0;
}
运行结果:

监视:

可以看出子进程运行完毕之后,在父进程sleep的时间内,子进程是Z状态(僵尸状态)

随后父进程wait,子进程被回收,不再是僵尸状态。

 

思考:

如果将代码中的sleep(10)删除,即表示父进程一开始直接执行到wait,那么情况又是什么样的呢?

运行结果:

 

监视:
 
总结:

进程等待能够回收子进程僵尸状态,Z->X

如果子进程没有退出,父进程必须在wait上进行阻塞等待,直到子进程僵尸,wait自动回收,返回。

 

2、waitpid

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID

演示:

(1)效果与wait相同

 waitpid(id,NULL,0)

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(0);
  }
  else 
  {
  //  sleep(10);
    printf("wait before\n"); 
   // pid_t rid = wait(NULL);
    pid_t rid = waitpid(id,NULL,0);
    
    printf("wait after\n");

    if(rid == id)
    {
      printf("wait sucess, pid:%d\n",getpid());
    }
  }



  return 0;
}

(2) status

status是一个int的整数,32bit,我们只考虑status的低16位。status的低16位被划分为三部分:

它的低七位是对应的信号,次低八位是退出的退出码。而剩下的1个bit位是core dump标志。

 

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(2);
  }
  else 
  {
  //  sleep(10);
    printf("wait before\n"); 
   // pid_t rid = wait(NULL);
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    
    printf("wait after\n");

    if(rid == id)
    {
      printf("wait sucess, pid:%d, status:%d\n",getpid(), status);
    }
  }



  return 0;
}

 

思考:

我们设置的退出码是2,那么为什么status显示的是512呢?

 退出码是2,根据上面status比特位的分区,我们可以写出status低16位:

那么该二进制转换成十进制,就是512。

 所以,我们不能对status进行整体使用。

使用:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(2);
  }
  else 
  {
  //  sleep(10);
    printf("wait before\n"); 
   // pid_t rid = wait(NULL);
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    
    printf("wait after\n");

    if(rid == id)
    {
      printf("wait sucess, pid:%d, rpid:%d, exit sig:%d, exit code:%d\n",getpid(), rid, status&0x7F, (status>>8)&0xFF);
    }
  }



  return 0;
}

 

如此,我们就可以正确显示该进程的退出信号和退出码了。

总结:
  1. 当一个进程异常(收到信号),exit code是没有意义的。
  2. 判定有没有收到信号,exit sig:0(sucess)
  • exit sig:0,exit code: 0 :代码跑完,结果正确。
  • exit sig:0,exit code: 非0 :代码跑完,结果不正确。
  • exit sig:非0   :中间出异常,exit sig的数字表明出现了哪种异常。

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杯酒问苍天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值