【Linux】撕开进程等待的真面目!

本文详细解释了Linux进程中父进程等待子进程的原因,包括防止僵尸进程、获取子进程退出状态和同步执行。介绍了wait和waitpid系统调用以及阻塞和挂起的区别,以及Linux如何存储和检查子进程的退出信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么要有进程等待?

在Linux下,我们的父进程可能需要创建子进程去完成一些特定的任务,而我们的父进程需要获取子进程的一些信息,来判断子进程是否完成任务。
进程等待:父进程停止自己的执行,来等待子进程的结束,并获取其退出状态。这样做的原因有如下几点:
1.防止僵尸进程:如果我们的子进程比父进程先完成,父进程因为一些bug(比如死循环之类的)一直未能退出,导致子进程没有被及时回收,使得有一些资源占用内存的资源,这种叫资源泄露,而我们的进程等待可以有效的防止这样的情况发生。
2.获取子进程的退出状态:我们创建子进程通常是让子进程完成一些特定的任务,我们可以通过进程等待来获取子进程的退出状态,来判断子进程的任务完成情况。
3.同步子进程和父进程:假如父进程后续有一些内容需要子进程完成任务后才能进行,就可以通过等待的方式,等待子进程将任务完成,父进程再接着去完成后续的执行。

2.如何进行进程等待?

我们的linux系统之下提供了两个系统调用接口,分别为waitwaitpid

这里的
wait和waitpid都包含在<sys/wait.h>的头文件里面。
这里的第一行wait的返回值pid_t其实就是一个size_t类型的整数,返回的是等待的子进程的pid,里面的参数stat_loc是一个int类型的指针变量,里面存储的就是我们子进程的退出信息。
第二行的waitpid返回的也是我们父进程等待的子进程的pid,
第一个参数我们可以有多种选择,当我们选择-1的时候,表示父进程等待任意一个子进程,或者我们也可以写入一个pid,指定父进程去等待一个子进程,
第二个参数也是存储我们子进程的退出信息的,
第三个参数通常我们给一个0,表示默认的状态,就是等待子进程,什么也不做,或者我们可以传入一个WNOHANG,设置当前的等待状态为非阻塞轮询。就是我们在等待子进程的时候去做一些其他事情,因为我们的子进程不退出时,我们的wait返回的一直是0,我们就可以通过判断为0来判断出我们现在处于等待状态,趁着等待的时候去做一些其他事情。

3.阻塞和挂起,status退出信息怎么存储?

wait是Linux下进程等待的一个接口,它默认父进程是以阻塞状态去等待我们的子进程的。
那么什么是阻塞状态?
阻塞状态就是我们的父进程在等待子进程,子进程在没有退出的时候,父进程什么事情也做不了,它只能一直等待,直到子进程结束,就是该进程没有达到某一条件就无法继续下去,就一直等到该条件满足的时候,才能继续进行。这种状态就是阻塞状态。这是一种被动的状态。
那么什么是挂起状态呢?
挂起就是我们的进程主动退出,不占用cpu和资源,然后只要唤醒又能继续执行的一种状态。
存储退出信息的status:我们的退出状态只是一种状态,那么我们只需要有一个作为标志的东西来代表是或者不是这个状态即可。所以,我们的Linux操作系统将一个int类型的数取它的二进制位的前16位来存储退出信息,其中前8位表示异常退出,次8位表示退出码。第8位是coredump标志位,来检测是否异常退出。
在这里插入图片描述
原理很简单,就是检测前8位是否为0,如果为0,那么前8位没有收到信号,程序没有发生异常,程序发生异常会转化为信号发送给相关的内容,然后这个进程就会被kill。
wait默认进程是以阻塞的方式等待的。
然后我们如何查看退出信息呢?
我们可以通过status&0x7F来查看低7位的信息,来判断程序有没有异常。
通过(status>>8)&0xFF来查看次8位的信息,来查看退出码。
我们还有另外一种方式来查看我们的退出信息。
在Linux操作系统下,封装了两个宏,分别是WIFEXITED(查看是否正常退出)和WEXITSTATUS(查看退出码),这两个宏本质上就是封装了上面的位操作。

4.如何进行这个过程的?

父进程等待子进程,子进程结束后,会将退出信息exitcode和signcode存储到进程的PCB中,也就是task_struct中,然后我们的父进程调用wait或者waitpid,就会去相对应的pid去找子进程,查看子进程的突出信息,然后将退出码和异常码整合起来,拷贝到一个status的整型数据中,这样就获取了我们子进程的退出信息。
然而会有人思考?为什么不直接设置一个全局变量,然后直接将退出信息放到这个全局变量中呢?
因为我们的进程是具有独立性的,虽然我们创建出来的子进程的代码和父进程一样,但是子进程一但发生有数据的更改,就会重新在磁盘中寻找新的位置,映射到页表中,这样就不会发生和父进程的数据起冲突,这样就使得我们更改的数据,只能子进程自己去访问,父进程看到的那个全局变量的数据依然是原来的数据。是没有被更改的数据。
那么为什么不直接让父进程去访问子进程的PCB来查看退出信息,而要通过调用wait或者waitpid接口呢?
因为我们的操作系统是一个管理者的身份,它要管理好我们的进程,如果父进程越过了操作系统的管理直接访问子进程的PCB,万一它进行了一些非法操作,比如修改退出码这些行为,是非常危险的,非常不安全。所以我们要通过封装系统调用接口来查看退出信息,让操作系统管理起来我们的进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

「已注销」

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

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

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

打赏作者

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

抵扣说明:

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

余额充值