wait/waitpid(重点)介绍

谢谢你的阅读,如有错误请大佬留言

目录

引子:

waitpid

返回值介绍

参数介绍

pid

status

options:


引子:

 当一个进程创建子进程后,如果子进程工作结束后会进入僵尸状态,等待父进程回收子进程资源(退出码,退出信号,子进程pid),如果父进程进入死循环或者程序执行时间过长,那么子进程将会一直处于僵尸状态,占用内存空间,这是对我们不利的一种状态,这种状态连kill -9 pid 都无法解决问题,因为你无法杀死一个以及死(Z/D,僵尸状态其实也属于死亡进程,只是未被清理)的状态。那么,如何防止这样的情况呢?

我们可以调用两个系统接口,来处理子进程僵尸状态:

pid_t wait(int *status);                                                                                                                  pid_t waitpid(pid_t pid, int *status, int options);
让我们先介绍这两个的概念。

看一下代码:

 我们的wait和waitpid的作用就是会暂停当前进程的执行,直到有信号到来或者子进程结束。总的来说,wait()的作用就是阻塞父进程,等待子进程。

但是我们的waitpid还有一种非暂停等待子进程的过程。

这里我们主要学waitpid/当我们的waitpid学习后,wait也明白了作用 

waitpid

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

返回值介绍

返回值:

        当正常返回的时候waitpid返回收集到的子进程的进程ID;

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

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

参数介绍

pid

1、(重点)pid=-1 等待任意一个子进程退出。

waitpid(-1,NULL,0);
//等待任意的子进程退出

2、(重点)pid>0 等待指定pid进程退出。

waitpid(1234,NULL,0);
//等待pid为1234的子进程退出

(次重)pid=0 等待进程组GID 与当前进程GID的子进程结束(也就是等待同一个进程组中的任何子进程);

waitpid(0,NULL,0);
//等待GID等于当前进程GID的子进程退出

(次重)pid<-1等待进程组识别码为 pid 绝对值的任何子进程。 

等待进程组 GID 为 pid 绝对值的进程组中的任何子进程;

GID 是组ID (Group Identify),表示组的身份唯一标识
UID 是用户ID (User Identify),表示用户身份唯一标识

status

先理解实现:

        int类型的指针,我们需要在调用处定义。然后传入函数,获取信息。

int sta=0;
waitpid(-1,&sta,0);//返回型参数

这里我们根据sta会取到子进程退出信号,退出码core dump等等信息。为什么一个变量可以获得这么多的信息呢?因为他是一个4字节类型,有32位比特位,所以我们分区块,获取数据,前16位比特位我们暂且不管,我们来看看后16位比特位给我们什么信息。

当进程正常退出,遇见exit/main中return。

退出码位后16位的前8位数据。(正常退出,结果正确/错误)

 如果子进程在运行期间发生越界访问或除0等严重错误时,发送信号,程序中断,这时候进程执行不到退出码,所以退出码没有意义,然后后7位为退出的信号

 如何查看退出码:先右移8个比特位再位运算

int sta=0;
waitpid(-1,&sta,0);
printf("code:%d",(std>>8)&0xff);//右移后,使用位运算取到退出码
printf("code:%d",WEXITSTATUS(status));//使用宏,其实底层也是位运算,返回子进程错误码。

 如何查看退出信号:直接位运算

int sta=0;
waitpid(-1,&sta,0);
printf("code:%d",std&0x7f);//使用位运算取到退出信号,0正常退出,非0退出信号
printf("code:%d",WIFEXITED(status));//使用宏,其实底层也是位运算,
//判断子进程是否正常退出,正常返回真,非正常返回假,bool返回类型

两个宏:

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)

WIFSIGNALED(status):如果子进程异常退出,获取退出信号,正常返回0(查看进程异常退出信号)

WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

实战使用:

正常退出:

 

异常退出 

发现正常退出时候信号为0,有退出码:123;

而异常退出的时候信号为非0,子进程提前结束无退出码;


options:

        0:若pid指定的子进程没有结束,父进程挂起。若正常结束,则返回该子进程的ID。

        WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。正常结束,则返回该子进程的ID。(异常返回-1)

                这里我们介绍一下什么是进程阻塞的概念。

阻塞:指有障碍而不能通过,无法畅通。我们waitpid一般设置为阻塞状态等待子进程返回,        但是我们也可以让进程以非阻塞状态进行等待子进程结束。我第一次理解的时候,这是什么意思?

让我们画图理解下:

A等待B去游玩,但是B在工作,A等待B完成工作

而这的等待有,两个方式:原地等待与边等边做自己的工作。

1、原地等待(阻塞状态):

if(fork()==0)
{
    //.....
    printf("子进程未结束工作\n");
    //.....
    exit(0);
}
waitpid(-1,NULL,0);//阻塞状态等待子进程结束
//....

2、边做自己的事情等待(非阻塞)

if(fork()==0)
{
    //.....
    printf("子进程未结束工作\n");
    //.....
    exit(0);
}
while(1){
    if(0==waitpid(-1,NULL,WNOHANG));//非阻塞状态等待子进程结束
    {
        //father doing own business
    }
    else
    {
        //接收到子进程pid(非0)退出等待
        break;
    } 
}
//....

 还记得wait吗

其实wait(NULL)等价于waitpid(-1,NULL,0);阻塞状态等待任意子进程结束,不需要返回值参数。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云的小站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值