当前位置: 首页 > news >正文

【Linux手册】进程等待:必要性剖析与wait、waitpid等多种方式实操指南

前言

在前面的一篇关于进程状态的文章中谈到Linux中有一种进程是僵尸进程,处于僵尸进程的进程会一直维护着自己的PCB对象以及退出的相关信息,等着父进程来获取,如果父进程一直不来就会导致进程一直处于僵尸进程,占据着内存资源造成内存泄漏 ,而获得子进程的退出信息就要通过进程等待。本文将详细介绍进程等待的各种方式以及底层原理。

为什么要进程等待

在前言部分已经谈到了部分进程等待的必要性,以下对其必要性做个总结:

  1. 让父进程来获取处于僵尸进程的子进程,对子进程进行回收,防止内存泄漏
  2. 进程一旦进入僵尸状态,不能被杀死(kill -9),所以必须通过进程等待的方式来对子进程进行回收;
  3. 父进程要知道分配给子进程的任务完成的如何 ,必须通过进程等待来获取子进程的退出情况;
  4. 通过进程等待能够保证子进程在没有完成任务时父进程不会死亡(在后面解释原因),保证父进程是最后一个释放的进程能够获取所有进程的退出信息。

什么是进程等待

进程等待的概念很简单,就是通过系统调用接口wait()和waitpid()让父进程获取子进程的相关信息,让子进程进行释放。关于是什么和为什么都很容易理解,我们将重点放在这些系统调用接口如何使用,以及是如何工作的。

系统调用接口

关于进程等待的系统调用接口有三个:
在这里插入图片描述

  1. pid_t wait(int* status);
  2. pid_t waitpid(pid_t id,int* status,int options);
  3. int waitid(idtype_t idtype, id_t id, siginfo_t * infop, int options);
    其中使用最多的就是前两种,本文也会重点介绍着两种。

pid_t wait(int* status)

  • 返回值类型是pid_t相当于整形,可以存储一个整形。waitpid的返回值就是父进程等待到的子进程的PID;
  • 参数有一个:
    • status输出型参数 ,通过传址的方式获取子进程的退出数据;
      父进程可以选择是否获取子进程的返回数据,如果不进行获取仅仅是为了让子进程释放资源,在传参的时候传NULL即可。
      以下是不获取子进程的返回数据的代码:
      在这里插入图片描述

以下是程序运行情况,左边是代码运行的具体情况,右边是一个简单的监视窗口。
在这里插入图片描述

现象:fork()创建子进程确实出现了两个进程在同时运行,在子进程运行完毕之后子进程进入了Z状态,即僵尸状态等待父进程来获取子进程的结果,当父进程完成进程等待后子进程确实被销毁了。

通过wat确实可以对子进程进行回收,并且因为wait()参数只有一个,导致wait会等待任意一个子进程不能指定等待哪一个进程;

status

父进程是通过形参来获取子进程的返回状态的,那他是如何通过一个status来获取的呢???

status是一个int* 类型的指针,传值调用和传址调用的主要区别就在于,传址调用是形参的改变会影响实参,所以通过status就可以获取子进程中的数据。
关于进程的终止,在之前的博客中就谈到过:进程终止一共分为3中:

  • 进程执行完毕,返回值正确;
  • 进程执行完毕,返回值错误;
  • 进程异常终止。
    因为进程结束的情况有多种可能,这也就意味着status中要能够包含这些情况。

在32位机器下,一个整形有32个比特位,可以通过不同的比特位来代表不同的信息从而将子进程的退出信息存储起来,具体来说就是:

在这里插入图片描述

通过将一个整形的不同不为进行分割就可以实现存储不同数据。
通过按位与的操作就可以获取到不同不为的信息:

  • (* status)&(0x7F):获取前7位得到异常信息,其中无异常信息用0表示;
  • ==(* status>>8)&(0xFF):获取第子进程的退出码。 ==
    系统中也有一些宏能帮助我们将status转换为进程退出信息:WIFEXITED(status)检测进程是否正常退出;WEXITSTATUS(status)获取进程的退出码…

status在底层是如何实现的呢???

在子进程中起始已经存储了处于僵尸状态的子进程异常信息已经退出码。通过将这些信息以^按位或的方式拷贝到status上即可。

***能够通过一个全局变量来获取子进程的退出信息???

这是一个典型的错误,因为进程之间具有独立性,即使你使用了一个全局遍历让自己子进程和父进程同时访问,但是当子进程要对全局变量进行修改的时候会进行写实拷贝,无法将信息传给父进程。

pid_t wait()会等待任意一个进程,并且如果子进程还在运行就会让父进程一直等待。
而另一个接口waitpid可以实现指定等待的子进程以及如何等待。

pid_t waitpid(pid_t id,int* status,int options)

waitpid与wait相比,其参数增加了;

  • 首先就是id,可以指定父进程等待哪一个子进程了;
  • 其次就是options,可以对父进程等待方式进行调整。

关于id,只需要将fork返回给父进程的PID传给waitpid即可实现等待具体的子进程;
关于options,指定等待方式。 wait的等待方式是阻塞等待,如果子进程还在运行,父进程就会一直等;这样势必会浪费时间和资源。
waitpid中可以通过参数来设定是阻塞式等待还是非阻塞式等待:0表示阻塞时等待,WNOHANG表示非阻塞式等待。
如果使用非阻塞式等待,父进程不需要一直等待子进程,父进程也可以先干一些自己的事过一会再来获取释放子进程的资源;这也就使得父进程需要循环式的问子进程时候运行完毕,这种方式被称为非阻塞轮询
在这里插入图片描述

虽然可以以这种方式让父进程边做自己的,边等待;但是我们还是以等待子进程为主,所以不要给父进程分配太多的任务。

http://www.lqws.cn/news/564841.html

相关文章:

  • IDE/IoT/实践小熊派LiteOS工程配置、编译、烧录、调试(基于 bearpi-iot_std_liteos 源码)
  • 软件测试 selenium
  • 【innovus基础】- 如何手动画线?
  • 【技术追踪】CLAIM:临床导向的 LGE 增强技术用于实现真实且多样化的心肌瘢痕合成与分割
  • 基于云的平板挠度模拟:动画与建模-AI云计算数值分析和代码验证
  • 青少年编程与数学 02-022 专业应用软件简介 01 设计与创意类软件:Adobe Creative Cloud
  • Wpf布局之UniformGrid面板!
  • MCP 中间件机制正式发布:FastMCP 的「责任链」进化
  • rollupOptions 详细讲解,如何优化性能
  • ali PaddleNLP docker
  • MATLAB GUI界面设计 第七章——高级应用
  • 机器学习8——神经网络下
  • 手机流量监控App(GlassWire)使用指南
  • WPF两种绑定方式的分析
  • ACE之ACE_Dev_Poll_Reactor
  • 高性能 List 转 Map 解决方案(10,000 元素)
  • 阿里云-接入SLS日志
  • HarmonyOS NEXT仓颉开发语言实战案例:健身App
  • HarmonyOS NEXT仓颉开发语言实战案例:小而美的旅行App
  • [分布式并行] 流水线并行 PP(NaivePP/GPipe/F-then-B/PipeDream/1F1B)
  • MCPA2APPT 智能化演示文稿系统:A2A、MCP、ADK 三大架构全流程自动化
  • 区块链技术: 稳定币USDC的工作原理
  • 【八股消消乐】消息队列优化—消息丢失
  • python pyecharts 数据分析及可视化(2)
  • 基于Pandas和FineBI的昆明职位数据分析与可视化实现(三)- 职位数据统计分析
  • MAC 地址在 TCP 网络中的全面解析:从基础概念到高级应用
  • 【Redis原理】Redis事务与线程模型
  • StarRocks 3.5 新特性解读:Snapshot 快照恢复、大导入性能全面升级、分区管理更智能
  • opensuse/debian grub启动界面太模糊?
  • Wpf布局之WrapPanel面板!