父子进程之间的等待(wait和waitpid的介绍+原理),status的介绍+恢复退出码(位运算+宏),非阻塞等待(宏),signal查看

news2024/11/26 11:56:43

目录

父子进程之间的等待

介绍

为什么要有等待

内存泄漏

如何等待

介绍

pid_t wait (int* status)

介绍

status指针

示例

​编辑

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

pid

 options

WNOHANG -- 非阻塞等待

示例

status

查看status

status问题

正常退出时,恢复退出码

位运算

进程崩溃,查看signal

引入

kill指令

示例 -- 野指针

示例 -- kill -9

为什么一定要通过上面的这些函数拿到退出信息

那么,这些问题wait / waitpid 是如何解决的呢?


父子进程之间的等待

介绍

通常用于实现协作和同步,以确保父进程等待子进程完成 / 等待子进程的某个事件

为什么要有等待

  • 在某些情况下,父子进程需要在执行过程中相互协同工作,以确保程序的正确性和完整性
  • 等待可以用于协调它们的活动,使它们按照某种特定的顺序执行任务
  • 父进程可能需要等待这些子进程完成执行,以便获取子进程的结果、收集信息或继续执行其他操作
  • 只有当父进程获取到子进程的退出状态信息时, 才会回收子进程资源(所以,如果父进程提前退出,将会造成子进程的资源泄漏)

内存泄漏

  • 这里的内存泄漏是指进程的task_struct还保留在内存中(也就是系统资源泄漏)
  • task_struct由os维护,其他人没有权限来释放,只能等待父进程回收 / 父进程退出后由init进程回收
  • 而我们平常说的内存泄漏是指进程在堆上开辟的空间没有被释放
  • 但其实一旦进程退出,这些由语言申请的空间都会被释放掉

如何等待

介绍

 头文件:

pid_t wait (int* status)

介绍
  • 用于父进程等待子进程的终止,并获取其退出状态
  • 如果当前没有子进程终止,父进程将被阻塞,等待一个子进程终止(也就是阻塞式等待)
  • 当一个子进程终止后,父进程会解除阻塞,并获取已终止子进程的pid(返回值),如果没有子进程终止,返回-1
status指针
  • 用于存储子进程的退出状态信息
  • 当该位置有参数时,由os提供该值
  • 如果不关心子进程的退出状态,可以传递NULL
示例

下面的代码流程是:

  • 创建一个子进程,子进程打印信息后睡眠5s,
  • 而父进程打印信息后睡眠7s,再等待进程状态变化
  • (其中的2s内可以看到子进程处于僵尸状态)
  • 后调用wait函数,用以回收已终止子进程的资源

可以看到,我们成功等待到了子进程:

 

子进程24295从僵尸状态Z+ -> 进程退出了,说明父进程等待子进程成功后,就释放掉了子进程的资源

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

pid
  • 如果为-1,则代表等待任意一个子进程终止(与wait()等价)
  • >0,它在等待指定的子进程
 options

默认是0,进行阻塞式等待

  • 此时父进程不做任何事,在等待队列中等待子进程的状态改变
  • 不占用cpu的时间片,这期间调度器调用其他可用进程
  • 阻塞的上层表现 -- 该进程无反应(因为cpu没有调度它)
WNOHANG -- 非阻塞等待
  • 宏定义(系统提供的大写标识位:一般都是宏定义,将没有特殊意义的数字定义成宏,使用时更加清晰)
  • 如果指定的子进程状态未改变,立即返回0 
  • 此时,父进程就可以执行waitpid后面的代码了(可以在等待的过程中完成一些小的工作模块)
  • 父进程在继续执行其他任务的同时,周期性地调用waitpid函数,以不断检查子进程的状态,从而及时获取子进程的退出状态
示例

可以看到,在父进程在等待子进程的过程中,依然在工作中

最终成功等待到子进程

 

status

和wait中的status用法一样

如果为waitpid(-1,NULL,0),则与wait(NULL)等价,看到的结果相同

查看status

如果我们尝试查看status呢?就可以使用waitpid(ret,&status,0):

我们让子进程睡眠5s后,带着退出码=2023退出,然后由父进程等待子进程退出,拿到退出码

 但是,结果似乎并不是我们想象中的那样(虽然子进程成功退出了,但是status的值很奇怪捏):

拿到的退出码怎么会是59136呢?

status问题

为什么上面的代码会出现值不一样的情况呢?

实际上status在函数内部并不是当做一个整数来对待,而是拆成32位bit位

其中低16位是我们需要了解的

正常退出时,恢复退出码
  • 如果程序执行完毕 (可以通过 宏(WIFEXITED) / 退出码 来判断是否正常退出)
  • 它会将实际的退出码放入[status的低16位]的后8位,然后将该数作为status的值
  • 所以我们得到的status会比设置的退出码(2023)大很多
位运算
  • 可以通过位运算的方式,将原本的退出码还原 (status>>8) & 0x0000 00ff
  • 右移8位是为了将退出状态移到该数的低8位,然后按位与拿到低8位
  • 也可以通过拿到该值 (WEIXTSTATUS)
进程崩溃,查看signal
引入
  • 如果进程崩溃提前终止了呢?这时的退出状态就没有意义了(会是0)
  • 其实想一想,运行的程序崩溃 本质上就是 os将这个进程杀死了
  • 那它是如何在茫茫进程中,单单选中了崩溃的进程把它杀死了呢?
  • 是通过程序发送信号通知os的
kill指令
  • 实际上,我们的kill指令就是通过os向进程发送信号,来对进程进行操作
  • 其中,信号是有编号的,1-31是普通信号,我们要学的也就是这31个信号
  • 然后,通过将 信号 放入 status的低7位 (第8位是core dump标志,在gdb调试崩溃程序中用到)
  • 我们可以通过按位与拿到低7位(& 0x0000 007f)
示例 -- 野指针
示例 -- kill -9

除了出现错误使程序崩溃,也可以是外力直接杀掉

  • 当子进程在死循环时,可以使用kill指令杀掉它(通过发送信号)

为什么一定要通过上面的这些函数拿到退出信息

  • 如果设置为全局变量呢?似乎可以拿到
  • 但其实,因为你要根据不同的判断条件来修改退出码,所以此时必定发生写时拷贝
  • 那么就会导致父子进程中的那个全局变量实际上有两个,父进程无法拿到子进程的变量,进程之间具有独立性

  • 除此之外,信号你又该如何拿到呢?

那么,这些问题wait / waitpid 是如何解决的呢?

  • 首先,那些退出信息也是数据,它就被存放在描述进程的pcb中
  • 还记得僵尸进程吗?
  • 为什么它有害,就是因为它的task_struct还保留在内存中,占用着资源
  • 必须要由父进程拿到子进程的退出码,才能释放它
  • 但是,进程之前不是有独立性吗?父进程是如何拿到子进程中的退出码的?
  • 实际上是由os完成的
  • os会自动回收子进程的资源,并将退出状态信息传递给父进程
  • 那么,wait和waitpid也是一样的道理,也是os完成实际的工作

  • wait和waitpid是系统调用,它是由os提供的接口
  • 因此由os维护的task_struct自然可以被自己的接口调用啦!!!
  • 所以,父进程是无法拿到子进程内部的信息的,但是os帮它拿到了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1170667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hive 解析 JSON 字符串数据的实现方式

文章目录 通过方法解析现实示例 通过序列化实现示例 通过方法解析现实 在 Hive 中提供了直接解析 JSON 字符串数据的方法 get_json_object(json_txt, path),该方法参数解析如下: json_txt:顾名思义,就是 JSON 字符串;…

上线Spring boot-若依项目

基础环境 所有环境皆关闭防火墙与selinux 服务器功能主机IP主机名服务名称配置前端服务器192.168.231.177nginxnginx1C2G后端服务器代码打包192.168.231.178javajava、maven、nodejs4C8G数据库/缓存192.168.231.179dbmysql、redis2C4G Nginx #配置Nginxyum源 [rootnginx ~]…

一文让你彻底明白,理解I/O多路复用

在讲解该技术之前,我们需要预习一下文件以及文件描述符。 什么是文件 程序员使用I/O最终都逃不过文件这个概念。 在Linux世界中文件是一个很简单的概念,作为程序员我们只需要将其理解为一个N byte的序列就可以了: b1, b2, b3, b4, ......…

HIT_OS_LAB2 调试分析 Linux 0.00 多任务切换

操作系统实验二 2.1 实验目的 通过调试一个简单的多任务内核实例,使大家可以熟练的掌握调试系统内核的方法;掌握Bochs虚拟机的调试技巧;通过调试和记录,理解操作系统及应用程序在内存中是如何进行分配与管理的; 2.2…

0002Java安卓程序设计-基于Uniapp+springboot菜谱美食饮食健康管理App

文章目录 开发环境 《[含文档PPT源码等]精品基于Uniappspringboot饮食健康管理App》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功 编程技术交流、源码分享、模板分享、网课教程 🐧裙:776871563 功能介绍&#xff…

javassmmysql爱心捐赠物资维护系统09536-计算机毕业设计项目选题推荐(附源码)

摘要 随着信息技术的快速发展,计算机应用已经进入成千上万的家庭。随着物资数量的增加,物资库存管理也存在许多问题。物资数据的处理量正在迅速增加,原来的手工管理模式不适合这种形式。使用计算机可以完成数据收集、处理和分析,减…

Mac苹果电脑分辨率修改管理 安装SwitchResX 完美解决

SwitchResX for Mac是一款Mac应用程序,可帮助您更好地管理和控制显示器分辨率和其他显示设置。使用SwitchResX,您可以创建自定义分辨率、旋转屏幕、调整显示器色彩配置等。 1. 自定义分辨率:SwitchResX允许用户创建自定义的屏幕分辨率&#…

【广州华锐互动】刑事纠纷3D模拟还原提高警方调查效率

随着科技的发展,刑事纠纷的调查和破解变得越来越依赖技术的支持。其中,3D模拟还原技术在刑事纠纷处理过程中发挥着越来越重要的作用。那么,刑事纠纷3D模拟还原的意义是什么呢? 首先,3D模拟还原技术可以帮助警方更真实、更准确地重…

2023最新版本 FreeRTOS教程 -4-队列集

队列集概述 解决任务读取多个队列的卡死问题的办法 如下图 如果队列1为空则任务挂起则不能再读取2 3 4队列 API函数(创建队列集) QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength )API函数(加入队列集) BaseType_t xQueueAddToSet( QueueSetMembe…

C#中LINQtoSQL只能在.NetFramework下使用,不能在.net 下使用

目录 一、在net7.0下无法实现LINQtoSQL 1.VS上建立数据库连接 2.VS上创建LINQtoSQL 二、在.NetFramework4.8下成功实现LINQtoSQL 1.VS上建立数据库连接 2.VS上创建LINQtoSQL 三、结论 四、理由 本文是个人观点,因为我百般努力在.net7.0下无法实现LINQtoSQL的…

自动化测试篇:Java+selenium+appium自动化测试详解

一、启动测试机或者Android模拟器(Genymotion俗称世界上最快的模拟器,可自行百度安装) 同时,我也准备了一份软件测试视频教程(含接口、自动化、性能等),需要的可以直接在下方观看,或…

JAVA智慧工地管理系统源码基于微服务

智慧工地是将互联网的理念和科技引入施工现场,从施工现场源头抓起,大程度的收集人员、安全、环境、质量等关键业务数据。通过结合物联网、大数据、互联网、云计算等技术建立云端大数据管理平台,形成端云大数据的体系与模式,这就是…

thinkphp漏洞复现

thinkphp漏洞复现 ThinkPHP 2.x 任意代码执行漏洞Thinkphp5 5.0.22/5.1.29 远程代码执行ThinkPHP5 5.0.23 远程代码执行ThinkPHP5 SQL Injection Vulnerability && Sensitive Information Disclosure VulnerabilityThinkPHP Lang Local File Inclusion ThinkPHP 2.x 任…

20.6 OpenSSL 套接字分发RSA公钥

通过上一节的学习读者应该能够更好的理解RSA加密算法在套接字传输中的使用技巧,但上述代码其实并不算完美的,因为我们的公钥和私钥都必须存储在本地文本中且公钥与私钥是固定的无法做到更好的保护效果,而一旦公钥与私钥泄密则整个传输流程都将…

开源检测数据库是否明文存储工具——OpenDLP的使用教程

前言 这些天Darren洋在做项目安全test调研的过程中,发现了一款非常不错的可自定义敏感数据类型的检测数据库是否明文存储工具。 OpenDLP 是一个开源项目,提供用于数据丢失预防(DLP)的工具。它允许自定义扫描规则,包括对…

一、Hadoop初始化配置(final+ubuntu保姆级教程)

1、配置虚拟机 三台虚拟机,分别为node1、node2、node3,内存分别为4G、2G、2G,现存最好为(>40G),如下: 2、修改主机名 分别打开三台虚拟机,root用户输入一下命令: no…

openLayers--绘制多边形、获取视图的中心点、获取当前地图等级、设置地图等级

openLayers绘制多边形、获取视图中心点 前言效果图1、导入LineString2、创建添加多边形3、定义多变形样式4、获取当前视图的中心点5、获取当前视图等级6、设置地图等级 前言 上一篇文章在vue项目中绘制了openlayers绘制了地图和标记点,本篇文章讲解openlayers绘制多…

Java医院HIS系统源码

Java医院HIS系统源码 项目描述 该项目是用springbootlayuishiro写的医院管理系统,该系统的业务比较复杂,数据库一共有36张表。项目的视频业务参考文档,都在百度云盘中。可以先看看视频和参考文档。 运行环境 jdk8mysqlIntelliJ IDEAmaven…

Docker学习——③

文章目录 1、Docker Registry(镜像仓库)1.1 什么是 Docker Registry?1.2 镜像仓库分类1.3 镜像仓库工作机制1.4 常用的镜像仓库 2、镜像仓库命令3、镜像命令[部分]4、容器命令[部分]4.1 docker run4.2 docker ps 5、CentOS 搭建一个 nginx 服…

英伟达显卡深度学习训练微调环境安装清单

可以考虑 安装完操作系统后,安装更新及其他基础软件如gcc cmake, 再安装英伟达几件套(这里列出了四个) 如果自带的python版本在3.8或以上,再安装python常用库。 python版本不能太低,看你要跑的代码的需求了…