【Linux详解】进程等待 | 非阻塞轮询

引入

为什么?是什么?怎么办

是什么?

进程等待是指父进程暂停自己的执行,直到某个特定的子进程结束或发生某些特定的事件。

为什么?

  • 僵尸进程刀枪不入,不可被杀死,存在内存泄露
  • 获取进程的执行情况,知道我布置给子进程的任务,它完成的怎么样了–可选

怎么办

wait 函数

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

测试:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>int main (void) 
{pid_t id = fork();if (id == 0) {// childwhile (1) {printf("我是子进程,我正在运行... Pid: %d\n", getpid());sleep(1);}}else {printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());sleep(20);   // 为了便于观察,我们让父进程休眠20s// 苏醒后,父进程执行 wait,耐心地等待子进程pid_t ret = wait(NULL);  // 暂且将status参数设置为NULLif (ret < 0) {printf("等待失败!\n");}else {printf("等待成功!\n");   // 此时 Z → X}sleep(20);  // 子进程退出后,再让父进程存在一段时间}
}

在这里插入图片描述

为什么是交替型,不是一个执行完?//了解循环的细节

fork 创建子进程后,父进程会首先执行并打印这条信息,其中 <父进程的pid> 是父进程的进程ID。截不下就没截了

  • 父进程打印一次消息后休眠20秒:
    • 父进程仅在创建子进程后打印一次消息,然后休眠20秒等待观察子进程的活动,不再进行其他操作。

通过这种方式,父进程和子进程能够并发地执行各自的任务,并且我们通过延迟父进程的退出能观察到子进程的连续活动。

整个程序执行流程如下:
  1. 父进程打印:

    yamlCopy code
    我是父进程: pid: 1234,我将耐心地等待子进程!
    
  2. 子进程每秒打印一次:

    yamlCopy code
    我是子进程,我正在运行... Pid: 5678
    

    (此循环持续到子进程被终止)

  3. 通过终端输入 kill 5678 终止子进程。

  4. 父进程20秒后苏醒并等待子进程结束后,打印:

    textCopy code
    等待成功!
    

之后,父进程再休眠20秒并继续存在一段时间后退出


waitpid

刚才讲的 wait 并不是主角,因为其功能比较简单,在进程等待时用的更多的是 waitpid

waitpid 可以把 wait 完全包含,wait 是 waitpid 的一个子功能。

参数

  • pid
    

    :要等待的子进程的进程ID。根据传入的值可以指定等待任何子进程、特定进程ID的子进程、任何同一进程组的子进程或者任何同一会话的子进程。

    • 如果 pid 大于零,waitpid 将等待指定进程ID的子进程结束。
    • 如果 pid 等于 -1,waitpid 将等待任意子进程结束,等同于 wait 函数。
  • status:一个指向整型的指针,是一个输出型参数,它将用于存储子进程的终止状态

  • options
    

    :用于指定等待行为的附加选项。

    • 传入0表示以默认行为等待子进程。(阻塞等待中再讲)

返回值

  • 如果 waitpid 成功,返回值是已终止子进程的进程ID
  • 如果出现错误,返回-1,并且会设置 errno 变量来指示具体错误原因。

Z状态,其本质上就是将自己的 task_struct 维护起来(代码可以释放,但是 task_struct 必须维护)。所谓的 wait/waitpid 的退出信息,实际上就是从子进程的 task_struct 中拿出来的,即 从子进程的 task_struct 中拿出子进程退出的退出码,拷贝到父进程中

在这里插入图片描述

status

该参数是一个 输出型参数 (即通过调用该函数,从函数内部拿出来特定的数据)。整数的低 16 位,其中又可以分为 最低八位次低八位(具体细节看图):

img

1.次低八位:拿子进程退出码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>int main (void) 
{pid_t id = fork();if (id == 0) {int cnt = 5;   // 循环5次// childwhile (1) {// 五秒之内运行状态printf("我是子进程,我正在运行... Pid: %d\n", getpid());sleep(1);// 五秒之后子进程终止cnt--;if (cnt == 0) {break; }}exit(233);   // 方便辨识,退出码我们设置为233,这是我们的预期结果}else {printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());// ***** 使用waitpid进行进程等待int status = 0;  // 接收 waitpid 的 status 参数pid_t ret = waitpid(id, &status, 0);if (ret > 0) {   // 等待成功printf ("等待成功,ret: %d, 我所等待的子进程退出码: %d\n", ret,(status>>8)&0xFF);}}
}

status 并不是整体使用的,而是区域性使用的,我们要取其次低八位。我们可以用 位操作 来完成,将 status右移八位再按位与上 0XFF,即 (status>>8)&0xFF ,就可以提取到 status 的次低八位了。

在这里插入图片描述

waitpid 经过系统调用,来读取子进程的pcb(eg. task_st…),这是为什么呢

操作系统不相信任何人,父进程用户无法直接读取子进程的 pcb ,要通过系统调用的接口

在这里插入图片描述

2.初识 core dump(核心转储)

在这里插入图片描述

它是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。目前只需要知道,该信息是用于调试的。

3.最低七位:提取子进程的退出信号

刚才我们讲的 wait/waitpid 和次低八位的时侯,都是关于进程(exit) 的 正常退出。

如果进程 异常退出 呢?我们来模拟一下进程的异常退出。

💬 模拟异常退出的情况,让子进程一直跑,父进程一直等。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>int main (void) 
{pid_t id = fork();if (id == 0) {// 子进程一直不退出,父进程会一直等待。// childwhile (1) {printf("我是子进程,我正在运行... Pid: %d\n", getpid());sleep(1);}exit(13);}else {printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());int status = 0;pid_t ret = waitpid(id, &status, 0);if (ret > 0) {   // 等待成功printf("等待成功,ret: %d, 我所等待的子进程退出码: %d\n, 退出信号是: %d", ret, (status>>8)&0xFF, status&0x7F);}}
}

现在我们直接 while(1) 死循环让子进程往死里跑,此时父进程由于调用了 waitpid,就会一直等待子进程,父进程就会持续阻塞

父进程看到子进程kill了,终于可以不用等了,可以给子进程收尸了

在这里插入图片描述

可以发现,使用-9号信号kill掉进程时,进程的退出信号就是9,然而当进程由于信号异常终止时,此时进程退出码是无意义的!

所以进程的等待可以理解为是 父进程在等给子进程退出记录


非阻塞轮询

options ->阻塞方式

waitpid(pid,&status,WNOHANG);

WNOHANG就是wait no hang,hang也就是悬挂,也就是非阻塞,等待子进程死亡,若父进程执行到waitpid时,子进程还没退出,则函数返回0后接着运行下面的代码,若执行到waitpid后子进程已经退出则返回退出子进程的pid

假如要期末考试了,我想找小张去自习室帮我复习,小张自己也在复习,我打电话问他什么时候复习完了,可以出门,情况解释如下

WNOHANG 夯住,非阻塞+循环

我给小张间隔打电话寻求帮忙,自己干等在楼下

阻塞式调用

打电话一直不挂

非阻塞轮询+自己的事情(最高效)

间隔打电话,自己也在复习

在这里插入图片描述

返回值

pid_t

ret_pid=0–所等待的条件还没有就绪,>0成功返回退出码,<0失败

代码验证

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{pid_t id = fork();if(id<0){perror("fork");exit(1);}if(id==0)//子进程代码{int count = 5;while(count){printf("[%d]我是子进程,我的pid是: %d\n",count,getpid());sleep(1);count--;}exit(55);//子进程执行完代码后退出}//父进程代码while(1)//循环访问子进程退出情况{int wait = waitpid(id,NULL,WNOHANG);if(wait>0)//子进程退出成功{printf("子进程退出成功,子进程pid: %d\n",wait);break;}else if(wait==0)//子进程还没退出,父进程干自己的事情{//此处简单模拟父进程干的事情printf("我是父进程,我现在要干一些别的事情\n");}else //等待子进程退出失败{perror("waitpid");exit(1);}sleep(1);}return 0;
}

在这里插入图片描述

⚠️注:这里父进程可以执行任一任务,我使用printf打印,只是为了明显的看到父进程是没有阻塞等待的!


进程退出的宏

为了增加可读性,定义了接口宏,来查找退出码

WEXITSTATUS WIFEXITED,在这之前,我们再思考一个问题:

❓ **思考:**一个进程退出时,可以拿到退出码和推出信号,我们先看谁?

一旦程序发现异常,我们只关心退出信号,退出码没有任何意义。

所以,我们先关注退出信号,如果有异常了我们再去关注退出码。

WEXITSTATUS 宏用于查看进程的退出码,若非 0,提取子进程退出码。

WEXITSTATUS(status)

WIFEXITED 宏用于查看进程是否正常退出,如果是正常终止的子进程返回状态,则为真。

WIFEXITED(status)

waitpid意义:

  1. 返回记录子进程内核的数据结构

  2. Z->X

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

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

相关文章

Linux_实现简易日志系统

目录 1、认识可变参数 2、解析可变参数 3、打印可变参数 3.1 va_list 3.2 va_start 3.3 va_arg 3.4 va_end 3.5 小结 4、实现日志 4.1 日志左半部分 4.2 日志右半部分 4.3 日志的存档归类 结语 前言&#xff1a; 在Linux下实现一个日志系统&#xff0c;该日…

ffmpeg图片视频编辑器工具的安装与使用

title: ffmpeg图片视频编辑器工具的安装与使用 tags: [ffmpeg, 图片, 音频, 视频, 工具, 流媒体] categories: [工具, ffmpeg] FFmpeg是一个开源的命令行工具&#xff0c;广泛用于处理视频和音频文件&#xff0c;包括转换格式、剪辑、混流、解码、编码等。以下是一些基本的FFmp…

java项目总结6

目录 1.双列集合 2.map的三种遍历方式&#xff1a; 1.键找值 2.键值对 3.lambda遍历map 3.HashMap 例子&#xff1a;统计字符出现次数 4.LinkedHashMap 5.TreeMap 6.可变参数 7.Collections: 1.双列集合 双列集合特点&#xff1a; 定义Map<String&#xff0c;St…

Linux中的管道符‘|‘以及SQL(DQL,DCL)

ls 指令 语法&#xff1a; ls [选项][目录或文件] 功能&#xff1a; 对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含文件。 -…

自注意力机制和多头注意力机制区别

Ref&#xff1a;小白看得懂的 Transformer (图解) Ref&#xff1a;一文彻底搞懂 Transformer&#xff08;图解手撕&#xff09; 多头注意力机制&#xff08;Multi-Head Attention&#xff09;和自注意力机制&#xff08;Self-Attention&#xff09;是现代深度学习模型&#x…

昇思25天学习打卡营第19天|Pix2Pix实现图像转换

1. 学习内容复盘 Pix2Pix概述 Pix2Pix是基于条件生成对抗网络&#xff08;cGAN, Condition Generative Adversarial Networks &#xff09;实现的一种深度学习图像转换模型&#xff0c;该模型是由Phillip Isola等作者在2017年CVPR上提出的&#xff0c;可以实现语义/标签到真实…

点胶系统实战1-项目介绍

准备实战开发如下图的多轴点胶系统实战课程&#xff0c;内容设计界面开发、运动板块开发、任务管理、点胶的控制等。我们将和进入这个领域的初学者门一起进步。 有感兴趣的小伙伴&#xff0c;可以关注点赞&#xff0c;或评论区反馈你们的重点关注的内容&#xff0c;那些部分我…

Postman使用指南①网页版使用

postman官网地址&#xff1a;Postman API Platform 进入后点击右上角免费注册&#xff0c;注册后登录 登录之后即可在网页使用&#xff0c;无需下载

线上问题---反思与回顾

线上问题一&#xff1a;麦哲伦2.0 人群配置不生效 发现背景&#xff1a;产品发现三层模型部分计划个别测试计划圈选人群特征与数仓统计数据的人群不一致&#xff0c;向值班人员反馈 根因定位&#xff1a; &#xff08;1&#xff09;用户配置三层模型计划时&#xff0c;配置单…

RNN 交叉熵

RNN善于处理时序 序列数据 简单RNN 展开就是 LSTM 遗忘门f_t决定上期记忆保留多少 隐藏层 在神经网络中&#xff0c;隐藏层指的是除了输入层和输出层之外的层&#xff0c;它们的输出不会直接用于网络的最终输出&#xff0c;而是作为中间步骤用于提取和转换数据。因此&#x…

【网络安全】实验五(身份隐藏与ARP欺骗)

一、本次实验的实验目的 &#xff08;1&#xff09;了解网络攻击中常用的身份隐藏技术&#xff0c;掌握代理服务器的配置及使用方法 &#xff08;2&#xff09;通过实现ARP欺骗攻击&#xff0c;了解黑客利用协议缺陷进行网络攻击的一般方法 二、搭配环境 打开三台虚拟机&#…

SQL Server特性

一、创建表 在sql server中使用create table来创建新表。 create table Customers( id int primary key identity(1,1), name varchar(5) ) 该表名为Customers其中包含了2个字段&#xff0c;分别为id&#xff08;主键&#xff09;以及name。 1、数据类型 整数类型&#xff…

Towards Accurate and Robust Architectures via Neural Architecture Search

基于网络架构搜索的准确性与鲁棒性结构研究 论文链接&#xff1a;https://arxiv.org/abs/2405.05502 项目链接&#xff1a;未开源 Abstract 为了保护深度神经网络免受对抗性攻击&#xff0c;对抗性训练因其有效性而受到越来越多的关注。然而&#xff0c;对抗训练的准确性和鲁…

扩散模型笔记

长参数“T”决定了生成全噪声图像所需的步长。在本文中&#xff0c;该参数被设置为1000&#xff0c;这可能显得很大。我们真的需要为数据集中的每个原始图像创建1000个噪声图像吗?马尔可夫链方面被证明有助于解决这个问题。由于我们只需要上一步的图像来预测下一步&#xff0c…

vue2 webpack使用optimization.splitChunks分包,实现按需引入,进行首屏加载优化

optimization.splitChunks的具体功能和配置信息可以去网上自行查阅。 这边简单讲一下他的使用场景、作用、如何使用&#xff1a; 1、没用使用splitChunks进行分包之前&#xff0c;所有模块都揉在一个文件里&#xff0c;那么当这个文件足够大、网速又一般的时候&#xff0c;首…

【C++】cout.self()函数

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文作为 JohnKi 学习笔记&#xff0c;借鉴了部分大佬案例 &#x1f4e2;未来很长&#…

工地/矿区/电力/工厂/环卫视频智能安全监控反光衣AI检测算法的原理及场景应用

一、引言 随着科技的快速发展&#xff0c;特别是在智能交通和安全生产领域&#xff0c;对于夜间或弱光环境下的人员识别和安全监控需求日益凸显。反光衣作为一种重要的安全装备&#xff0c;被广泛应用于道路施工、工地作业、夜间巡逻、安全生产等场景&#xff0c;旨在提高人员的…

Meerkat:第一个统一视听空间和时间定位的MLLM

大型语言模型&#xff08;LLMs&#xff09;在各种自然语言处理任务中表现出色&#xff0c;达到了理解和推理能力的人类水平精度。此外&#xff0c;借助新兴的指令微调范式&#xff0c;这些语言模型可以被赋予遵循开放式自然语言指令的能力&#xff0c;甚至可以与其他模态&#…

机器学习第四十六周周报 FMP

文章目录 week46 FMP摘要Abstract1. 题目2. Abstract3. FMP3.1 优化框架3.2 优化器 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程 5. 结论6.代码复现1. FMP2. fairGNN小结参考文献 week46 FMP 摘要 本周阅读了题为Chasing Fairness in Graphs: A GNN Architecture Per…

【Spring Cloud】微服务的简单搭建

文章目录 &#x1f343;前言&#x1f384;开发环境安装&#x1f333;服务拆分的原则&#x1f6a9;单一职责原则&#x1f6a9;服务自治&#x1f6a9;单向依赖 &#x1f340;搭建案例介绍&#x1f334;数据准备&#x1f38b;工程搭建&#x1f6a9;构建父子工程&#x1f388;创建父…