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

详讲Linux下进程等待

3.进程等待

引言:什么是进程等待

想象有两个小伙伴,一个是 “大强”(父进程 ),一个是 “小强”(子进程 )。大强给小强安排了任务,比如去收集一些石头。                                                                
1. 大强想知道小强啥时候把任务完成,就用了个办法:他跟小强说,等你干完活,记得跟我说一声。然后大强就不做别的事了(从运行状态变成阻塞状态 )在那等着小强的消息,把 CPU 让给其他小伙伴(其他就绪进程 )去用。
2.小强呢,就跑去收集石头了。等他把石头收集完(子进程完成任务并终止 ),就赶紧给大强发个信号,说 “我干完啦”。大强收到这个信号后,就从等着的状态(阻塞状态 )醒过来(变成就绪状态 ),然后 CPU 就又可以让大强接着做他后面的事啦,比如看看小强收集的石头合不合格(处理子进程的终止状态 )。

在计算机里,wait 或者 waitpid 这些函数就像是大强用来等小强消息的工具,通过它们,父进程就能等着子进程把活干完,再接着往下走 。

3.1 进程等待必要性

  • 之前讲过,⼦进程退出,⽗进程如果不管不顾,就可能造成‘僵⼫进程’的问题,进⽽造成内存 泄漏。
  • 另外,进程⼀旦变成僵⼫状态,那就⼑枪不⼊,“杀⼈不眨眼”的kill -9 也⽆能为⼒,因为谁也 没有办法杀死⼀个已经死去的进程。
  • 最后,⽗进程派给⼦进程的任务完成的如何,我们需要知道。如,⼦进程运⾏完成,结果对还是 不对,或者是否正常退出。
  • ⽗进程通过进程等待的⽅式,回收⼦进程资源获取⼦进程退出信息.

 3.2 进程等待的⽅法

3.2.1 wait⽅法

#include<sys/types.h>

#include<sys/wait.h>

pid_t wait(int* status);

返回值:

成功返回被等待进程pid,失败返回-1。

参数:

输出型参数,获取⼦进程退出状态,不关⼼则可以设置成为NULL

wait 函数的作用机制

wait 函数是一个系统调用,其作用是使父进程暂停执行,等待其子进程中的任意一个终止。当父进程调用 wait 时,内核会检查是否有已经终止的子进程。如果有,wait 会获取该子进程的终止状态信息,并返回该子进程的进程 ID,父进程继续执行后续代码;如果没有子进程终止,父进程就会被阻塞(进入睡眠状态 S),直到有子进程终止才会被唤醒并继续执行。

第一种 正常,回收⼦进程资源获取⼦进程退出信息.

wait 函数会阻塞父进程,直到它的一个子进程终止。当子进程终止后,wait 函数返回终止子进程的进程 ID 

第二种 如果等待子进程,子进程没有退出,父进程会阻塞在wait调用出吗?

在同一账户开两个窗口 

 while :; do ps ajx | head -1 && ps ajx | grep wlw5 ; sleep 1;done |grep -v grep

man 2 wait

 3.2.2 waitpid⽅法

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:

                       当正常返回的时候waitpid返回收集到的⼦进程的进程ID;

                        如果设置了选项WNOHANG,⽽调⽤中waitpid发现没有已退出的⼦进程可收集,则返回0;

                        如果调⽤中出错,则返回-1,这时errno会被设置成相应的值以指⽰错误所在;

参数:

             pid

                         Pid=-1,等待任⼀个⼦进程。与wait等效。

                          Pid>0.等待其进程ID与pid相等的⼦进程。

             status: 输出型参数

                         WIFEXITED(status): 若为正常终⽌⼦进程返回的状态,则为真。(查看进程是否是正常退出)

                         WEXITSTATUS(status): 若WIFEXITED⾮零,提取⼦进程退出码。(查看进程的退出码)

                          options:默认为0,表⽰阻塞等待

                          WNOHANG: 若pid指定的⼦进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该⼦进程的ID。

获取id的值 ,与wait效果一样

当pid的值>0时, id+1仿造等待其进程ID与pid相等的⼦进程。 

接收指定的子进程所以,导致建立的子进程变成僵尸进程🧟‍♀️

 

 问题一 获取退出码

首先定义了 int status = 0; 用于存储子进程的终止状态信息。然后调用 pid_t rid = waitpid(id, &status, 0); ,其中 id 是要等待的子进程的进程 ID,&status 用于存储子进程的终止状态,0 表示默认的等待选项。 

为什么返回的 为什么不是1,而是256呢?

wait和waitpid,都有⼀个status参数,该参数是⼀个输出型参数,由操作系统填充。

如果传递NULL,表⽰不关⼼⼦进程的退出状态信息。

否则,操作系统会根据该参数,将⼦进程的退出信息反馈给⽗进程。

status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16

⽐特位):

可以把它当成一张位图来看,而其中整形这个变量一共32个比特位,其中高16位,低16位。

我们不管高16位,一个比特位要么0要么1,其中8-15是(退出状态码)后面的8位 全是0一旦后8位!0,异常退出,退出码毫无意义,那256就是2^8二的八次方=256。

的值正常终止的原因,如何获取呢?

(status>>8)&0xFF

  • 子进程的终止状态信息存储在 status 变量中,它包含了多种信息。在 Linux 中,子进程正常退出时,其退出状态码存放在 status 的低 8 位 。

  • status>>8 是将 status 的值右移 8 位,这样原本存放在低 8 位的退出状态码就移到了最低 8 位。

  • &0xFF 是进行按位与操作,0xFF 即二进制的 11111111 ,与右移后的 status 进行按位与操作,是为了只保留最低 8 位的值,也就是准确获取子进程的退出状态码 。通过打印这个值,可以知道子进程是以什么状态码退出的,有助于调试和了解子进程的执行结果。

 问题二获取代码异常终止信号

所有信号

 tatus&0x7F这是一个位运算表达式。在 Linux 中,子进程终止状态信息存储在 status 中,其中低 7 位(0x7F 即二进制的 01111111 )用于存储导致子进程终止的信号编号(如果子进程是因信号终止 )。通过与 0x7F 进行按位与操作,可以提取出这部分信号相关信息。如果子进程是正常退出(使用 exit 函数 ),那么这部分值为 0;如果是因信号(如 SIGTERMSIGKILL 等 )终止,就能获取到对应的信号编号。

 

获取子进程退出码和特殊信号

刚刚在获取子进程推出码和特殊信号时,我们用的是位操作,但计算机里面的或者是它对应的为了配套的操作里面,他不想让你作为未操作提取,所以他给我们提供了若干个宏,这时候看宏它可以帮我们直接去提取

WEXITSTATUS(status)

: 若WIFEXITED⾮零,提取⼦进程退出码。(查看进程的退出码)

 

 WIFEXITED(status):

若为正常终⽌⼦进程返回的状态,则为真,否则异常。(查看进程是否是正常退出)

 

阻塞调用和非阻塞调用

想象你去餐厅点餐:

  • 阻塞调用:就像你点完餐后,站在柜台前一直等着服务员把做好的餐递给你,期间啥也不干,啥也做不了,只能干等着。在这个过程中,你处于 “阻塞” 状态,一直被这件事绊住 。对应到编程里,比如父进程调用 wait 函数等待子进程结束,在子进程没结束前,父进程就卡在那里,不能去做其他事,这就是阻塞调用。

上面的例子都是阻塞调用

  • 非阻塞调用:类似你点餐后,没在柜台干等着,而是去旁边找个位置坐下,玩手机或者和朋友聊天。你告诉服务员做好了喊你,然后你可以同时做其他事。在编程中,像用 waitpid 函数时带上 WNOHANG 选项,父进程调用后,如果子进程没结束,它不会一直卡在那,而是马上返回去做自己其他的任务,这就是非阻塞调用 。

pid_ t waitpid(pid_t pid, int *status, int options);

                          WNOHANG: 若pid指定的⼦进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该⼦进程的ID。

  • 非阻塞调用两种情况

1.在餐厅点餐之后 ,你什么都不干,一直询问服务员好了没。‘’

 

2.在餐厅等服务员叫你的同时你干些事情。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>// 定义函数指针类型
typedef void (*func_t)();#define NUM 10  // 假设函数指针数组的最大长度// 以下是任务函数定义
void Download()
{printf("我是一个下载的任务...\n");
}void Flush()
{printf("我是一个刷新的任务...\n");
}void Log()
{printf("我是一个记录日志的任务...\n");
}// 注册函数
void registerHandler(func_t h[], func_t f)
{int i = 0;for (; i < NUM; i++){if (h[i] == NULL)break;}if (i == NUM)return;h[i] = f;h[i + 1] = NULL;
}int main()
{func_t handlers[NUM] = {NULL};registerHandler(handlers, Download);registerHandler(handlers, Flush);registerHandler(handlers, Log);pid_t id = fork();if (id < 0){perror("fork");exit(EXIT_FAILURE);}if (id == 0){// 子进程int cnt = 3;while (1){sleep(3);printf("我是一个子进程,pid : %d, ppid : %d\n", getpid(), getppid());sleep(1);cnt--;if (cnt <= 0){break;}}exit(10);}// 父进程while (1){int status = 0;pid_t rid = waitpid(id, &status, WNOHANG);if (rid > 0){if (WIFEXITED(status)){printf("wait success, rid: %d, exit code: %d, exit signal: %d\n",rid, WEXITSTATUS(status), status & 0x7F);}else{printf("子进程退出异常!\n");}break;}else if (rid == 0){// 函数指针进行回调处理int i = 0;for (; handlers[i]; i++){handlers[i]();}printf("本轮调用结束,子进程没有退出\n");sleep(1);}else{perror("waitpid");break;}}return 0;
}

相关文章:

详讲Linux下进程等待

3.进程等待 引言&#xff1a;什么是进程等待 想象有两个小伙伴&#xff0c;一个是 “大强”&#xff08;父进程 &#xff09;&#xff0c;一个是 “小强”&#xff08;子进程 &#xff09;。大强给小强安排了任务&#xff0c;比如去收集一些石头。 …...

JBoss + WildFly 本地开发环境完全指南

JBoss WildFly 本地开发环境完全指南 本篇笔记主要实现在本地通过 docker 创建 JBoss 和 WildFly 服务器这一功能&#xff0c;基于红帽的禁制 EAP 版本的重新分发&#xff0c;所以我这里没办法放 JBoss EAP 的 zip 文件。WildFly 是免费开源的版本&#xff0c;可以在红帽官网找…...

【网络原理】TCP协议如何实现可靠传输(确认应答和超时重传机制)

目录 一. TCP协议 二. 确定应答 三. 超时重传 一. TCP协议 1&#xff09;端口号 源端口号&#xff1a;发送方端口号目的端口号&#xff1a;接收方端口号 16位&#xff08;2字节&#xff09;端口号&#xff0c;可以表示的范围&#xff08;0~65535&#xff09; 源端口和目的…...

【国家能源集团生态协作平台-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…...

Java表达式1.0

Java开发工具 在当今的Java开发领域&#xff0c;IntelliJ IDEA已然成为了众多开发者心目中的首选利器&#xff0c;它被广泛认为是目前Java开发效率最快的IDE工具。这款备受瞩目的开发工具是由JetBrains公司精心打造的&#xff0c;而JetBrains公司总部位于风景如画的捷克共和国首…...

idea中导入从GitHub上克隆下来的springboot项目解决找不到主类的问题

第一步&#xff1a;删除目录下的.idea和target&#xff0c;然后用idea打开 第二步&#xff1a;如果有需要&#xff0c;idea更换jdk版本 原文链接&#xff1a;https://blog.csdn.net/m0_74036731/article/details/146779040 解决方法&#xff08;idea中解决&#xff09;&#…...

Android音视频开发

Android Framework 与音视频技术深度解析 一、Android音视频架构全景 ▶ 四层架构协同┌──────────────┐│ 应用层 │ ▶ MediaPlayer/ExoPlayer/Camera2 API调用└──────┬───────┘┌──────▼───────┐│ 框架层 │…...

【AI论文】CLIMB:基于聚类的迭代数据混合自举语言模型预训练

摘要&#xff1a;预训练数据集通常是从网络内容中收集的&#xff0c;缺乏固有的领域划分。 例如&#xff0c;像 Common Crawl 这样广泛使用的数据集并不包含明确的领域标签&#xff0c;而手动整理标记数据集&#xff08;如 The Pile&#xff09;则是一项劳动密集型工作。 因此&…...

Linux操作系统--环境变量

目录 基本概念&#xff1a; 常见环境变量&#xff1a; 查看环境变量的方法&#xff1a; 测试PATH 测试HOME 和环境变量相关的命令 环境变量的组织方式&#xff1a;​编辑 通过代码如何获取环境变量 通过系统调用获取或设置环境变量 环境变量通常具有全局属性 基本概念…...

Jenkins 多分支管道

如果您正在寻找一个基于拉取请求或分支的自动化 Jenkins 持续集成和交付 (CI/CD) 流水线&#xff0c;本指南将帮助您全面了解如何使用 Jenkins 多分支流水线实现它。 Jenkins 的多分支流水线是设计 CI/CD 工作流的最佳方式之一&#xff0c;因为它完全基于 git&#xff08;源代…...

精益数据分析(9/126):如何筛选创业路上的关键数据指标

精益数据分析&#xff08;9/126&#xff09;&#xff1a;如何筛选创业路上的关键数据指标 大家好&#xff01;在创业的漫漫长路中&#xff0c;数据就像一盏明灯&#xff0c;指引着我们前行的方向。但要让这盏灯发挥作用&#xff0c;关键在于找到那些真正有价值的数据指标。今天…...

C语言之图像文件的属性

&#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 图像文件属性提取系统设计与实现 目录 设计题目设计内容系统分析总体设计详细设计程序实现…...

LeetCode hot 100—分割等和子集

题目 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5, 5] 和 [11] 。…...

高等数学同步测试卷 同济7版 试卷部分 上 做题记录 上册期中同步测试卷 B卷

上册期中同步测试卷 B卷 一、单项选择题(本大题共5小题,每小题3分,总计15分) 1. 2. 3. 4. 5. 由f(2/n), n→∞可知 2/n→0, 即x→0. 二、填空题(本大题共5小题,每小题3分&#xff0c;总计15分) 6. 7. 8. 9. 10. 三、求解下列各题(本大题共5小…...

【算法】快速排序、归并排序(非递归版)

目录 一、快速排序&#xff08;非递归&#xff09; 1.原理 2.实现 2.1 stack 2.2 partition(array,left,right) 2.3 pivot - 1 > left 二、归并排序&#xff08;非递归&#xff09; 1.原理 2.实现 2.1 gap 2.1.1 i 2*gap 2.1.2 gap * 2 2.1.3 gap < array.…...

python-将文本生成音频

将文本生成音频通常需要结合 文本转语音&#xff08;TTS&#xff0c;Text-to-Speech&#xff09; 工具或库来实现&#xff0c;比如 Google TTS (gtts)、Amazon Polly、Microsoft Azure TTS 等。 一、使用 Google TTS (gtts) 将文本生成音频 gtts 是一个简单易用的 Python 库&a…...

[王阳明代数讲义]语言模型核心代码调研

语言模型核心代码调研 基于Consciciteation‌的才气张量持续思考综述将文本生成建模为才气张量网络扩散过程&#xff0c;实现非自回归推理通过才气张量的群-拓扑流形交叉注意力实现多模态推理&#xff0c;将输入压缩到低维空间持续迭代提出「条件计算提前终止」机制&#xff0c…...

4月19日记(补)算了和周日一块写了 4月20日日记

周六啊 昨天晚上又玩的太嗨了。睡觉的时候有点晚了&#xff0c;眼睛疼就没写日记。现在补上 实际上现在是20号晚上八点半了。理论上来说应该写今天的日记。 周六上午打比赛啦&#xff0c;和研究生&#xff0c;输了&#xff0c;我是替补没上场。没关系再练一练明天就可以变强…...

trivy开源安全漏洞扫描器——筑梦之路

开源地址&#xff1a;https://github.com/aquasecurity/trivy.git 可扫描的对象 容器镜像文件系统Git存储库&#xff08;远程&#xff09;虚拟机镜像Kubernetes 在容器镜像安全方面使用广泛&#xff0c;其他使用相对较少。 能够发现的问题 正在使用的操作系统包和软件依赖项…...

【实战中提升自己】内网安全部署之dot1x部署 本地与集成AD域的主流方式(附带MAC认证)

1 dot1x部署【用户名密码认证&#xff0c;也可以解决私接无线AP等功能】 说明&#xff1a;如果一个网络需要通过用户名认证才能访问内网&#xff0c;而认证失败只能访问外网与服务器&#xff0c;可以部署dot1x功能。它能实现的效果是&#xff0c;当内部用户输入正常的…...

[matlab]南海地形眩晕图代码

[matlab]南海地形眩晕图代码 请ChatGPT帮写个南海地形眩晕图代码 图片 图片 代码 .rtcContent { padding: 30px; } .lineNode {font-size: 12pt; font-family: "Times New Roman", Menlo, Monaco, Consolas, "Courier New", monospace; font-style: n…...

Web安全和渗透测试--day6--sql注入--part 1

场景&#xff1a; win11家庭版&#xff0c;edge浏览器 &#xff0c; sqlin靶场 定义&#xff1a; SQL 注入&#xff08;SQL Injection&#xff09;是一种常见的网络安全攻击方式&#xff0c;攻击者通过在 Web 应用程序中输入恶意的 SQL 代码&#xff0c;绕过应用程序的安全机…...

大模型在胆管结石(无胆管炎或胆囊炎)预测及治疗方案制定中的应用研究

目录 一、引言 1.1 研究背景与意义 1.2 研究目的 1.3 国内外研究现状 二、胆管结石相关理论基础 2.1 胆管结石概述 2.2 临床表现与诊断方法 2.3 传统治疗方法 三、大模型技术原理与应用优势 3.1 大模型基本原理 3.2 在医疗领域的应用潜力 3.3 用于胆管结石预测的可…...

MIT6.S081-lab4

MIT6.S081-lab4 注&#xff1a;本篇lab的前置知识在《MIT6.S081-lab3前置》 1. RISC-V assembly 第一个问题 Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf? 我们先来看看main干了什么&#xff1a; …...

精通 Spring Cache + Redis:避坑指南与最佳实践

Spring Cache 以其优雅的注解方式&#xff0c;极大地简化了 Java 应用中缓存逻辑的实现。结合高性能的内存数据库 Redis&#xff0c;我们可以轻松构建出响应迅速、扩展性强的应用程序。然而&#xff0c;在享受便捷的同时&#xff0c;一些常见的“坑”和被忽视的最佳实践可能会悄…...

[SpringBoot]快速入门搭建springboot

默认有spring基础&#xff0c;不会一行代码一行代码那么细致地讲。 SpringBoot的作用 Spring Boot是为了简化Spring应用的创建、运行、调试、部署等而出现的。就像我们整个SSM框架时&#xff0c;就常常会碰到版本导致包名对不上、Bean非法参数类型的一系列问题&#xff08;原出…...

理解.NET Core中的配置Configuration

什么是配置 .NET中的配置&#xff0c;本质上就是key-value键值对&#xff0c;并且key和value都是字符串类型。 在.NET中提供了多种配置提供程序来对不同的配置进行读取、写入、重载等操作&#xff0c;这里我们以为.NET 的源码项目为例&#xff0c;来看下.NET中的配置主要是有…...

C++面试八股文:智能指针

一、了解哪些智能指针&#xff1f; 回答&#xff1a;智能指针是用于管理动态分配的内存&#xff0c;行为类似于指针&#xff0c;但又具有自动管理内存的能力&#xff0c;所以称为智能指针。 首先说一下 auto_ptr和unique_ptr&#xff0c;它们都是独占式指针&#xff0c;同一时…...

nohup命令使用说明

文章目录 如何在后台运行程序呢&#xff1f;如何正常运行代码重定向呢&#xff1f;nohup: ignoring input 如何在后台运行程序呢&#xff1f; 使用nohup命令即可&#xff0c; nohup python dataset/ReferESpatialDataset.py >>dataset_20250417.log 2>&1 &n…...

MYSQL “Too Many Connections“ 错误解决

1.查询当前连接数 show status like "Threads_connected"; 2.查询数据库最大连接数 show variables like "max_connections" 3.查询所有活动连接 show processlist; 4.根据查询结果观察是否有长时间未被释放的连接 参数解释 : 字段说明id连接的唯一…...