【进程控制】超详细讲解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)处理退出码

相关文章
|
6月前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
82 3
|
8月前
|
安全
【进程通信】信号的捕捉原理&&用户态与内核态的区别
【进程通信】信号的捕捉原理&&用户态与内核态的区别
|
8月前
|
存储
【进程信号】信号阻塞的原理
【进程信号】信号阻塞的原理
|
8月前
|
Shell
【进程通信】利用管道创建进程池(结合代码)
【进程通信】利用管道创建进程池(结合代码)
|
4月前
|
算法 调度 UED
操作系统中的进程管理:原理与实践
在数字世界的心脏跳动着无数进程,它们如同细胞一般构成了操作系统的生命体。本文将深入探讨进程管理的奥秘,从进程的诞生到成长,再到最终的消亡,揭示操作系统如何协调这些看似杂乱无章却又井然有序的活动。通过浅显易懂的语言和直观的比喻,我们将一起探索进程调度的策略、同步机制的重要性以及死锁问题的解决之道。准备好跟随我们的脚步,一起走进操作系统的微观世界,解锁进程管理的秘密吧!
91 6
|
5月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
5月前
|
Linux API C语言
Linux源码阅读笔记02-进程原理及系统调用
Linux源码阅读笔记02-进程原理及系统调用
|
5月前
|
网络协议 安全 Unix
从孤岛到大陆:Python进程间通信,让你的代码世界不再有隔阂
【8月更文挑战第1天】在编程领域,Python进程曾像孤岛般各自运行于独立内存中。随项目复杂度增长,进程协同变得重要。Python提供了多种机制搭建这些孤岛间的桥梁。本文介绍四种常见进程间通信(IPC)方式:管道(Pipes)、队列(Queues)、共享内存(Shared Memory)及套接字(Sockets),并附示例代码展示如何实现信息自由流通,使进程紧密相连,共建复杂程序世界。
41 2
|
7月前
|
Python Windows
在 Windows 平台下打包 Python 多进程代码为 exe 文件的问题及解决方案
在使用 Python 进行多进程编程时,在 Windows 平台下可能会出现将代码打包为 exe 文件后无法正常运行的问题。这个问题主要是由于在 Windows 下创建新的进程需要复制父进程的内存空间,而 Python 多进程机制需要先完成父进程的初始化阶段后才能启动子进程,所以在这个过程中可能会出现错误。此外,由于没有显式导入 Python 解释器,也会导致 Python 解释器无法正常工作。为了解决这个问题,我们可以使用函数。
179 5
|
7月前
|
算法 Linux 调度
Linux进程——进程的创建(fork的原理)
Linux进程——进程的创建(fork的原理)
277 2