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

linux进程控制——进程等待——wait、waitpid

        前言:本节内容仍然是进程的控制,上一节博主讲解的是进程控制里面的进程创建、进程退出、终止。本节内容将讲到进程的等待——等待是为了能够将子进程的资源回收,是父进程等待子进程。 我们前面的章节也提到过等待, 那里的等待是进程等待硬件设备, 而这里是进程等待软件设备,也就是说——进程等待可以发生在硬件上面, 也可以发生在软件上面。 另外, 通过本节的学习, 友友们可以理解一个完整的进程控制是什么样的, 是怎么样的流程。 

        ps:本节内容适合学习了进程创建、退出与终止的友友们观看

为什么要有进程等待

        进程等待, 对于一个子进程来说, 如果子进程退出, 父进程不管不顾, 就可能造成僵尸进程的问题。 进而造成内存泄漏!!!

        进程等待的一个原因就是为了子进程能够在僵尸进程的时候被父进程回收, 防止内存泄漏。 ——僵尸进程无法被杀死,需要父进程等待来杀掉它, 从而解决内存泄漏问题。 

        第二个原因就是我们要通过进程等待获取子进程的退出情况。——知道我布置给子进程的任务, 它完成的怎么样了? ——要么关心, 要么不关心这个是可以选择的。

进程的等待是什么?

        进程等待就是通过系统调用, wait/waitpid, 来进行对子进程进行状态检测与回收的功能!

进程等待是怎么实现的?

        进程等待是如何实现的用一句话来说就是——父进程通过调用wait/waitpid进行僵尸进程的回收问题!               

        但是, 这里就有问题, wait接口和waitpid接口是什么? 这就是我们本篇文章着重讲解的知识点。 现在我们先来看一下man手册:

        wait是一个系统调用接口, 包含在sys/types.h头文件里。 定义就可以见上图, 然后里面的status参数暂时可以不考虑。

        wait和waitpid的作用就是等待一个进程, 当这个进程退出后, 那么父进程就可以等待子进程

 , 回收子进程的资源。 

wait和waitpid的返回值

返回值如果是大于零的, 那么就是等待成功, 并且是被等待的子进程的pid。

单进程等待

下面是实验(使用wait, waitpid和wait一样, 不用着急, waitpid后续会讲解)

        上面的代码就是先创建一个子进程, 然后子进程5s后变成僵尸进程被等待, 父进程10后运行等待, 然后关闭子进程。 但是这个程序很难观察到wait的作用,我们修改一下:

        将上图板块中的代码改成图中所示的样子。 然后运行程序, 我们就可以观察到:

多进程等待

上面是单进程的情况, 那么多个子进程的时候, wait等待的是哪一个进程呢? ——wait一次是等待一个进程, 是随机的。 而且只等待一个进程, 那么现在我们来试验一下,下面是代码:

我们运行后, 可以观察到, 5s后, 最后一个创建的子进程都已经是僵尸进程了。

然后随即等待, 全部等待成功后我们就会发现, 进程被回收了。 

 

阻塞等待 

那么我们现在思考一下, 当子进程没有变成僵尸, 一直在运行的时候, 父进程等待还有用吗?

现在看下面一个实验, 这里面创建了一个子进程, 这个子进程会无限次循环下去, 但是父进程会在10s后进入等待, 观察现象:

运行结果如下,可以发现, 其实子进程没有进入僵尸, 那么父进程的等待对不它不起效果。——这个其实就是父进程在wait这里发生了阻塞等待!!也就是说, 父进程不会退出, 一直等待子进程的返回。

        那么, 什么是阻塞等待——阻塞等待就是子进程不退出, 父进程默认在wait的时候, 也就是调用这个系统调用的时候, 不发生返回, 这个就叫做阻塞等待。

        知道了阻塞等待之后, 我们也知道, 任何进程都会变成僵尸进程, 然后被进程等待回收资源, 等待是必须的。 僵尸进程是必须的。——知道了这些, 我们就可以想到一个完整的进程控制代码就是:有创建(fork), 有终止(exit), 有等待(wait)。

waitpid

        现在我们来说一下waitpid。 waitpid的功能多于wait, wait是waitpid的子集。 

waitpid的第一个参数是等待的进程的pid(也就是说可以指定等待对象), 也可以传送-1, 表示随即等待和wait一样。 并且waitpid的返回值是等待的进程的pid。

        退出信息:

        退出信息是通过第二个参数, status获取到。 ——wait里面是第一个参数。 

        对于status, 这个动能可以使用可以不使用——也就是说可以传参, 也可以不传参。 status是一个指针, 意思是说将函数内部的数据通过status带出来, 也就是输出型参数。 

        并且这个int是被当做及部分使用的。 ——因为int有32给比特位, 其中八个或者十六个比特位表示一个东西, 另外又表示一个东西, 这里我们进行试验一下:

        首先我们要写或者退出结果必须顶一个整数变量, 然后取地址变量传给waitpid, 调用系统嗲用后获取相应的结果, 再带出这个结果, 然后status就会发生变化。

运行结果如下:

        这里之所以退出2816, 就要考虑几个问题:

        我们知道, 进程推出的时候, 主要有三种场景——退出结果正确, 推出结果不正确, 异常。 那么, 子进程退出, 父进程希望获取什么信息呢?

        首先:1、子进程代码是否异常?——不同信号表示不同异常

                   2、没有异常, 结果对吗? exitcode, 不对是因为什么呢? ——不同退出码表示不同原因

        那么, status最少能够获取这个进程是否发生了异常, 异常原因, 结果是否正确? 为什么?——这些信息都保存在了status的低16比特位, 并且这里我们只谈status的低16位。

        这里的低7位就是代表进程的终止信号, 如果进程异常退出, 这里会保存下来什么异常——比如除零错误, kill -9等等。

        这里的第八位是core dam标志——这个暂时不谈。

        前八位就是代表正常退出的状态。

        而我们的子进程上面是可以看到是正常退出——信号位0; 并且退出码为11, 二进制就是1011, 然后合起来就是0000 1011 0000 0000——这个二进制转化为十进制就是2816.

         现在我们来谈一下信号:

        我们就会发现, 这些信号里面没有0号信号——没有零号信号, 那么这个时候我们是不是就可以通过这个进程是否是零号信号, 来判断是否发生了异常? 

        一旦进程发生异常, 那么不同信号就会代表不同的异常, status就会待会不同的结果。

现在, 我们来考虑——父进程要拿到子进程状态数据, 为什么要调用wait等待系统调用呢? 直接用全局变量不行码?——答案是不可以, 我们知道, 父子进程是独立的, 如果在子进程里修改了这个全局变量, 本质上就是发生了写时拷贝, 父进程里面的全局变量并不会被修改。 所以不可以。

        现在我们想要将子进程的状态分开打印——打印信号和退出码, 怎么打印呢?

        下面是一个代码:

程序和上面一样, 但是打印的内容:

 那么我们给一个除零错误, 就会看到:

我们使用kill -9就可以看到:

非阻塞轮询

以上就是本节的全部内容, 下面是本节笔记:

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • uniapp自定义网格布局用于选择金额、输入框焦点事件以及点击逻辑实战
  • 【面试题】C++:面向对象的三大特性?
  • Cocos Creator文档学习记录
  • Java二十三种设计模式-外观模式(9/23)
  • 示例:在ML.NET中应用Model Builder模型生成器构建图片分类模型
  • 定位Oracle表空间问题
  • 基于若依框架开发的Spring Boot+Vue的MES(生产制造执行系统)是一种专为中小型工厂设计的ERP(企业资源计划)系统
  • Nerd Fonts
  • 如果你感到焦虑、精神内耗,那就跑步去吧!
  • Spring Cloud全解析:注册中心之Eureka服务发现
  • 前端 HTML 概述
  • MATLAB在科研领域的重要性
  • E25.【C语言】练习:修改二进制序列的指定位
  • LeetCode Medium|【3. 无重复字符的最长子串】
  • 41缺失的第一个正数【力扣】【C++】
  • 《剑指offer》分解让复杂问题更简单
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • 4个实用的微服务测试策略
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • CSS实用技巧
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • httpie使用详解
  • JavaScript-Array类型
  • JavaScript类型识别
  • React 快速上手 - 07 前端路由 react-router
  • spark本地环境的搭建到运行第一个spark程序
  • Spring声明式事务管理之一:五大属性分析
  • yii2权限控制rbac之rule详细讲解
  • 规范化安全开发 KOA 手脚架
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 原生js练习题---第五课
  • C# - 为值类型重定义相等性
  • Prometheus VS InfluxDB
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • # 数据结构
  • #WEB前端(HTML属性)
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • $.proxy和$.extend
  • (02)Unity使用在线AI大模型(调用Python)
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (六)c52学习之旅-独立按键
  • (三)Kafka离线安装 - ZooKeeper开机自启
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • **PHP二维数组遍历时同时赋值
  • .net 7和core版 SignalR
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福