【进程控制】超详细讲解wait和waitpid的原理(结合代码)

简介: 【进程控制】超详细讲解wait和waitpid的原理(结合代码)

前言

在了解了进程状态这一概念之后,我们明白了什么叫做僵尸进程:子进程退出,父进程“不管不顾”。而一旦存在僵尸进程,势必也会存在内存泄露问题,所以作为一个父进程,及时处理子进程的退出信息是他的责任。那么子进程的退出信息到底是什么?以及父进程怎么接收到子进程的退出信息?本文章重点围绕这两个问题展开叙述。

进程等待

进程等待是指一个进程暂停执行,等待另一个进程的结束。最常见的是父进程等待自己的子进程,或者父进程回收自己的子进程资源包括僵尸进程

等待方法有:wait函数和waipid函数

waitpid函数

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

waitpid返回导致waitpid函数返回的已终止子进程的PID。默认情况下(options=0),waipid会挂起调用程序的执行,此时父进程被阻塞直到它的等待集合中的一个子进程终止。等待集合的成员是由参数pid来确定的。

如果pid>0,那么等待集合就是一个单独的子进程,它的进程PID等于参数pid。

如果pid=-1,那么等待集合就是父进程的所有子进程。

查看执行waitpid过程中,父进程的状态

观察以下代码:

可以观察到在waitpid执行过程中父进程进入了阻塞状态。

参数option

可以通过将options设置为WONHANG、WUNTRACED和WCONTINUED的各种组合来修改默认行为。

WONHANG:挂起调用进程的执行,如果等待集合中的任何子进程都还没有终止,那么就立即返回(返回值为0).默认的行为是挂起调用进程,直到有子进程终止。在等待子进程终止的同时,可以做其他的动作

WUNTRACED:挂起调用进程的执行,直到等待集合中的一个进程变成终止或者被停止。返回的PID是等待导致waipid返回的子进程的PID.但我们想要检查已终止或者被停止的子进程时,可以用这个选项。

WCONTINUED:挂起调用进程的执行,直到等待集合中一个正在运行的进程终止或等待集合中一个被停止的进程收到SIGCONT信号重新开始执行

其中WONHANG选项可以使父进程发生非阻塞等待

什么叫非阻塞等待?

非阻塞等待是一种操作系统中的机制,它允许进程在等待子进程结束时,不必一直阻塞直到子进程退出。具体来说,当使用waitpid系统调用时,可以设置WNOHANG标志来启用非阻塞等待模式。如果子进程尚未结束,waitpid将立即返回,而不是等待子进程结束。这样,父进程可以在检测到子进程仍在运行时继续执行其他任务,并在稍后再次尝试检查子进程的状态,直到子进程结束。

以下代码可以观察到父进程在等待过程中,还可以做其他的事

如果带有WONHANG选项,waitpid如果返回值为0,说明子进程还没有终止,需要下一次重复进行等待。一般来说调用一次waitpid是不够的,因为不知道还要进行等待多少次,所以我这里配合循环等待。这样一种循环的非阻塞等待,就被称为非阻塞轮询方案

参数status

观察waitpid函数的声明,参数status是一个指针,能记录函数修改的值,也就是输出型参数。可以将参数设为NULL,意味着不关心子进程的退出信息。否则,status参数就记录着子进程退出信息。

status代表的整数有32个比特位,其中低16位的比特位记录着子进程的退出码和退出信号。

8-15位二进制转换为十进制表示的就是退出码,0-6位7个二进制表示的是退出信号。

假设截取到status的低16位二进制为:

0000 0001 0000 0000就表示子进程的退出码为1,退出信号为0(无异常)。

用以下代码测试status的值

了解了status的作用,也就知道了父进程是如何接收到子进程的退出信息的了。同样,也很清楚的明白了,子进程的退出信息无非就是退出码和退出信号。作为父进程有权利也有义务去了解一个子进程的退出信息。

wait 函数

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

wait函数作用和waitpid相识,相当于waitpid的简单版本,返回被等待进程的pid(一有子进程终止就返回),失败返回-1。其参数status的含义与waitpid中的一致。

WIFEXITED和WEXITSTATUS

WIFEXITED和WEXITSTATUS是两个宏,专门用来对子进程退出信息status做处理。

WIFEXITED(status) 可以 检查子进程是否是正常退出,如果正常则饭返回true,否则就是false.

WEXITSTATUS(status) 可以返回子进程的退出码,实际上就是取出status的第8-15位二进制,在用十进制表示。

这两个宏通常搭配使用。

先用WIFEXITED(status)判断子进程是否发生异常,如果没有再用WEXITSTATUS(status)处理退出码

相关文章
|
1月前
|
安全
【进程通信】信号的捕捉原理&&用户态与内核态的区别
【进程通信】信号的捕捉原理&&用户态与内核态的区别
|
1月前
|
存储
【进程信号】信号阻塞的原理
【进程信号】信号阻塞的原理
|
1月前
|
Shell
【进程通信】利用管道创建进程池(结合代码)
【进程通信】利用管道创建进程池(结合代码)
|
16天前
|
算法 Linux 调度
Linux进程——进程的创建(fork的原理)
Linux进程——进程的创建(fork的原理)
12 2
|
1月前
【进程通信】Syetem V 共享内存(结合代码模拟通信)
【进程通信】Syetem V 共享内存(结合代码模拟通信)
|
1月前
|
Linux Shell 程序员
【进程控制】进程程序替换的原理以及exec函数族
【进程控制】进程程序替换的原理以及exec函数族
|
1月前
|
Shell 编译器 Linux
【进程概念】环境变量PATH(结合代码,超极容易理解)
【进程概念】环境变量PATH(结合代码,超极容易理解)
|
1月前
|
NoSQL Linux Shell
【进程概念】进程状态以及僵尸进程(结合代码)
【进程概念】进程状态以及僵尸进程(结合代码)
|
1月前
|
算法 Ubuntu Linux
【操作系统原理】—— 进程调度
【操作系统原理】—— 进程调度
12 0
|
1月前
|
存储 Ubuntu Unix
【操作系统原理】—— 进程管理
【操作系统原理】—— 进程管理
13 0

相关实验场景

更多