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

Linux系统:详解进程等待wait与waitpid解决僵尸进程

本节重点

  • 理解进程等待的相关概念
  • 掌握系统调用wait与waitpid的使用方法
  • 输出型status参数的存储结构
  • 阻塞等待与非阻塞等待

一、概念

进程等待是操作系统中父进程与子进程协作的核心机制,指父进程通过特定方式等待子进程终止并回收其资源的过程。这一机制的主要目的是避免子进程成为僵尸进程,从而释放系统资源并维护进程表的完整性。

二、进程等待的方法

2.1 wait与waitpid

2.1.1 wait

wait 是一个用于进程控制的系统调用,主要用于父进程等待其任意一个子进程终止,并回收子进程的资源(如进程表项)。

函数原型:

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

参数:

status :输出型参数,一个指向整数的指针,用于存储子进程的终止状态。如果不需要关心子进程的退出状态信息,可以传入NULL。 

返回值:

成功时返回终止的子进程的PID,失败时返回-1并设置errno。

代码示例:

#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>int main()
{//创建子进程:pid_t id=fork();if(id==0){//childint i=5;while(i){printf("我是一个子进程,PID->%d,PPID->%d\n",getpid(),getppid());sleep(1);i--;}exit(10);}else if(id>0){//parentint ret=0;printf("我是一个父进程,PID->%d\n",getpid());int _ret=wait(&ret);if(_ret>0){printf("wait success, child PID->%d,exitcode->%d\n",_ret,ret);}else{printf("wait fail,error->%d\n",errno);}}else{//id<0printf("fork fail\n");}return 0;
}

 运行结果:

注意事项:

系统调用wait默认等待方式是阻塞等待,也就是说当父进程调用 wait 或waitpid 时,它会阻塞在调用wait的一段代码行,直到有一个子进程终止父进程解除阻塞状态后才会执行后续代码。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程printf("Child process: PID = %d\n", getpid());sleep(2); // 模拟子进程工作exit(0);} else if (pid > 0) {// 父进程int status;printf("Parent process: Waiting for child to terminate...\n");wait(&status); // 阻塞,直到子进程终止printf("Child process terminated with status: %d\n", WEXITSTATUS(status));} else {perror("fork failed");}return 0;
}

2.1.2 waitpid

waitpid 是 Unix/Linux 系统中用于等待子进程状态变化的系统调用,是 wait 的增强版本。它允许父进程更灵活地控制等待行为,可以指定等待特定的子进程或进程组,并支持阻塞和非阻塞模式。

函数原型:

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

参数解析:

 pid: 指定要等待的子进程

  • pid > 0:等待进程 ID 为 pid 的子进程。
  • pid == 0:等待与调用进程同组的任意子进程。
  • pid < -1:等待进程组 ID 为 |pid| 的任意子进程。
  • pid == -1:等待任意子进程(等效于 wait)。

status:指向一个整数用来存储子进程的退出状态

options:控制waitpid的行为,可以是以下标志的按位或:

  • 0:阻塞模式,等待子进程终止。
  • WNOHANG:非阻塞模式,如果没有子进程退出,立即返回。
  • WUNTRACED:报告已停止但未终止的子进程状态。
  • WCONTINUED:报告已继续运行的子进程状态。

返回值:

成功:

  • 返回被等待子进程的 PID。
  • 如果没有子进程满足条件且设置了 WNOHANG,返回 0

失败:

  • 返回 -1,并设置 errno 指示错误原因。

代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>#define N 3int main() {pid_t pids[N];int i;// 创建多个子进程for (i = 0; i < N; i++) {pids[i] = fork();if (pids[i] == 0) {// 子进程printf("Child %d: PID = %d\n", i, getpid());sleep(i + 1);exit(i);}}// 父进程等待所有子进程终止for (i = 0; i < N; i++) {int status;pid_t result = waitpid(pids[i], &status, 0);if (result > 0) {if (WIFEXITED(status)) {printf("Child %d exited with status: %d\n", i, WEXITSTATUS(status));}} else {perror("waitpid failed");}}return 0;
}

运行结果:

Child 0: PID = 12346
Child 1: PID = 12347
Child 2: PID = 12348
Child 0 exited with status: 0
Child 1 exited with status: 1
Child 2 exited with status: 2

 注意事项:

 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源获得子进程的退出信息。

如果调用wait/waitpid时,子进程存在且正常运行,则进程可能会阻塞。

如果不存在该子进程,则立即出错返回。

2.3 获取子进程的status

在Linux系统中,父进程通过wait/waitpid来等待和回收子进程的相关资源并通过status参数返回子进程的退出信息,该参数是一个输出型参数由操作系统填充。

如果传递NULL表示不关心子进程的退出信息。

2.3.1 status参数的存储结构

ststus 不能简单当作整型来看待,可以当作位图来看待,其中包含了子进程的退出码与终止信号,如下图:

其低 16 位用于存储子进程的退出状态信息。具体来说:

  • 低 7 位:表示导致子进程终止的信号编号(如果子进程被信号终止)。
  • 第 8 位:表示是否生成了核心转储文件(core dump)。
  • 高 8 位:表示子进程的退出码(如果子进程正常退出)。

注意:

当进程正常终止时,低7位和第8位都为0,高8位存储子进程的退出码,可以通过位运算(ststus>>8)&0×FF或通过系统提供的宏来获取。

当进程异常终止或被信号所终止时,退出状态无意义故高8位都为0,终止信号存储在低7位中可以通过位运算status&0×7F或通过宏来获取。

2.3.2 用于解析ststus的宏

以下宏定义在<sys/wait.h>文件中,用于解析返回后的status参数。

子进程是否正常退出:

WIFEXITED(status)
  •  如果子进程正常退出(例如调用了 exit( ) 或 return ),则返回非零值(真)。
  • 否则返回0(假)。

 获取子进程的退出码:

WEXITSTATUS(status)
  •  如果 WEXITSTATUS(status) 返回真,则可以使用此宏获取子进程的退出码。
  • 退出码是子进程调用 exit(code) 或 return code 时指定的值。

检查子进程是否被信号终止(异常退出):

WIFSIGNALED(status)

 如果子进程被信号终止返回非零,否则返回0。

获取导致子进程终止的信号编号:

WTERMSIG(status)

 如果WTERMSIG(ststus)返回真,则可以使用此宏获取导致子进程终止的信号编号。

2.4 阻塞等待与非阻塞等待


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

系统调用waitpid的第三个参数options用来设置阻塞等待与非阻塞等待,默认为0表示阻塞等待,当传递宏WNHANG时表示非阻塞等待。

阻塞等待:

当waitpid处于阻塞等待时进程会阻塞于调用waitpid的代码段处(停止执行),直到等待的进程终止,waitpid才会返回继续执行后续代码。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{pid_t id=fork();int status;if(id==0){//childprintf("我是一个子进程,我的PID是%d,父进程PID%d\n",getpid(),getppid());sleep(10);exit(0);}else if(id>0){//parentpid_t ret=waitpid(id,&status,0);if(ret>0){printf("wait success!\n");}else{printf("wait fail!\n");}printf("这是父进程的后续代码\n");}else{perror("fork fail!");}return 0;
}

运行结果:

 非阻塞等待:

当waitpid处于非阻塞状态时,进程不会停止执行自己的代码,但waitpid会不断查询相应进程的状态信息直到被等待进程终止,期间waitpid的返回值一直是0。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>//函数指针类型:
typedef void (*func_t)();
#define NUM 5
func_t handers[NUM+1];void DownLoad()
{printf("我是一个下载的任务\n");
}
void Flush()
{printf("我是一个刷新的任务\n");
}
void Log()
{printf("我是一个记录日志的任务\n");
} //注册
void registerhanders(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()
{//注册函数:registerhanders(handers,DownLoad);registerhanders(handers,Flush);registerhanders(handers,Log);pid_t id=fork();int status;if(id==0){//childprintf("我是一个子进程,我的PID是%d,父进程PID为%d\n",getpid(),getppid());sleep(5);}else if(id>0){//parentwhile(1){int ret=waitpid(id,&status,WNOHANG);if(ret==0){printf("轮询结束,子进程未退出!\n");}else if(ret>0){printf("轮询结束,子进程退出!\n");break;}else{//ret<0perror("waitpid fail!\n");break;}sleep(1);//printf("这是父进程代码!\n");for(int i=0;i<NUM;i++){if(handers[i]!=NULL)handers[i]();}}}else{//id<0//fork fail!perror("fork fail!");}return 0;
}

如上述所示就是一段非阻塞进程等待的代码,父进程除了一次次查询子进程的进程状态之外也在执行自己的三个函数任务(下载任务,刷新任务,记录日志的任务),当子进程退出后父进程会立即回收子进程资源,接着整段程序结束。

运行结果:

相关文章:

Linux系统:详解进程等待wait与waitpid解决僵尸进程

本节重点 理解进程等待的相关概念掌握系统调用wait与waitpid的使用方法输出型status参数的存储结构阻塞等待与非阻塞等待 一、概念 进程等待是操作系统中父进程与子进程协作的核心机制&#xff0c;指父进程通过特定方式等待子进程终止并回收其资源的过程。这一机制的主要目的…...

6.7 ChatGPT自动生成定时任务脚本:Python与Cron双方案实战指南

ChatGPT自动生成定时任务脚本:Python与Cron双方案实战指南 关键词:定时任务调度, ChatGPT 代码生成, Cron 脚本开发, Python 调度器, 自动化更新系统 6.3 使用 ChatGPT 生成 Cron 调度脚本 在 GitHub Sentinel 的定期更新功能中,定时任务调度是核心模块。本节演示如何通过…...

K8S运维实战之集群证书升级与容器运行时更换全记录

第一部分&#xff1a;Kubernetes集群证书升级实战 tips:此博文只演示一个节点作为示范&#xff0c;所有的集群节点步骤都可以参考。 项目背景 某金融业务系统Kubernetes集群即将面临生产证书集中过期风险&#xff08;核心组件证书剩余有效期不足90天&#xff09;&#xff0c…...

IntelliJ IDEA clean git password

IntelliJ IDEA clean git password 清除git密码 方法一&#xff1a;&#xff08;这个要特别注意啊&#xff0c;恢复默认设置&#xff0c;你的插件什么要重新下载了&#xff09; File->Manage IDE Settings->Restore Default Settings以恢复IDEA的默认设置(可选); 清空…...

【已更新完毕】2025泰迪杯数据挖掘竞赛C题数学建模思路代码文章教学:竞赛智能客服机器人构建

完整内容请看文末最后的推广群 基于大模型的竞赛智能客服机器人构建 摘要 随着国内学科和技能竞赛的增多&#xff0c;参赛者对竞赛相关信息的需求不断上升&#xff0c;但传统人工客服存在效率低、成本高、服务不稳定和用户体验差的问题。因此&#xff0c;设计一款智能客服机器…...

2025年4月19日 记录大模型出现的计算问题

2025年4月19日 记录大模型出现的计算问题&#xff0c;用了四个大模型计算json的数值&#xff0c;3个错误&#xff0c;1个正确 问题 Class Train Val answer 2574 853 screen 5025 1959 blackBoard 7847 3445 teacher 8490 3228 stand…...

ACI EP Learning Whitepaper 3. Disabling IP Data-plane Learning 功能

目录 1. 使用场景 1.1 未disable IP data-plane learning时 1.2 disable IP data-plane learning后 2. 一代Leaf注意事项 3. L2 未知单播注意事项 1. 使用场景 Windows网卡的动态负载均衡绑定模式等。或多个设备共享相同VIP并通过ARP/GARP/ND来宣告VIP切换时,这些外部设…...

C++入门七式——模板初阶

目录 函数模板 函数模板概念 函数模板格式 函数模板的原理 函数模板的实例化 模板参数的匹配原则 类模板 类模板的定义格式 类模板的显式实例化 当面对下面的代码时&#xff0c;大家会不会有一种无力的感觉&#xff1f;明明这些代码差不多&#xff0c;只是因为类型不…...

计算机网络 - 在浏览器中输入 URL 地址到显示主页的过程?

第一步&#xff0c;浏览器通过 DNS 来解析 URL&#xff0c;得到相应的 ip 地址&#xff08;到哪里找) 和 方法&#xff08;做什么&#xff09; 第二步&#xff0c;浏览器于服务器建立 TCP 三次握手连接 第三步&#xff0c;建立好连接后&#xff0c;浏览器会组装 HTTP 请求报文…...

【教程】检查RDMA网卡状态和测试带宽 | 附测试脚本

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 检查硬件和驱动状态 测试RDMA通信 报错修复 对于交换机的配置&#xff0c;可以看这篇&#xff1a; 【教程】详解配置多台主机通过交换机实现互…...

(二)Trae 配置C++ 编译

Trae配置c编译 零 CMake 编译C0.1 下载安装0.2 安装设置0.3 三种编译方式(见 下文 一 二 三)0.4 调试 (见 下文四) 一 使用MSVC方式编译1.1 安装编译环境1.2安装插件1.3 设置文件 二 使用GCC方式2.1 安装编译环境2.1.1下载:[MinGw](https://gcc-mcf.lhmouse.com/)2.1.2安装:(以…...

Doris 本地部署集群重启后报错

报错描述 Docker 版本&#xff1a; apache/doris:fe-2.1.9 apache/doris:be-2.1.9 连接 MySQL 报错&#xff1a; ERROR 2003 (HY000): Cant connect to MySQL server on 127.0.0.1:9030 (111)FE 日志&#xff1a; INFO (UNKNOWN fe_e7cff187_69d4_42ee_90be_147e87310549(-1…...

日本公司如何实现B2B商城订货系统的自动化和个性化?

在日本构建具备前后台日文本地化、业务员代客下单、一客一价、智能拆单发货的B2B电商系统&#xff0c;需结合日本商业习惯与技术实现。以下是关键模块的落地方案&#xff1a; 一、系统架构设计 1. 前端本地化 语言与UI适配 采用全日语界面&#xff0c;包含敬语体系&#xff08…...

自动化测试相关协议深度剖析及A2A、MCP协议自动化测试应用展望

一、不同协议底层逻辑关联分析 1. OPENAPI协议 OPENAPI 协议核心在于定义 API 的规范结构&#xff0c;它使用 YAML 或 JSON 格式来描述 API 的端点、请求参数、响应格式等信息。其底层逻辑是构建一个清晰、标准化的 API 描述文档&#xff0c;方便不同的客户端和服务端进行对接…...

ReAct、CoT 和 ToT:大模型提示词推理架构的对比分析

ReAct、CoT 和 ToT&#xff1a;大模型提示词推理架构的对比分析 在大型语言模型&#xff08;LLM&#xff09;的研究与应用中&#xff0c;如何有效提升模型在复杂任务上的推理能力是关键问题之一。目前&#xff0c;ReAct&#xff08;Reasoning and Acting&#xff09;、CoT&…...

用魔法打败魔法——获取软件安装路径

用魔法打败魔法——获取软件安装路径 &#x1f31f;嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 背景普通方法用魔法一句话 1.首先新建‘PC自动化应…...

2024-04-19| Java: Documented注解学习 JavaDoc

在 Java 中&#xff0c;Documented 是一个元注解&#xff08;meta-annotation&#xff09;&#xff0c;用于标记其他注解&#xff0c;表明这些注解应该被包含在 JavaDoc 文档中。以下是关于 Documented 注解的作用的简要说明&#xff1a; 作用 记录注解信息到 JavaDoc&#x…...

Spring Boot常用注解全解析:从入门到实战

&#x1f331; Spring Boot常用注解全解析&#xff1a;从入门到实战 #SpringBoot核心 #注解详解 #开发技巧 #高效编程 一、核心启动与配置注解 1. SpringBootApplication 作用&#xff1a;标记主启动类&#xff0c;整合了Configuration、EnableAutoConfiguration和Component…...

【重学Android】1.关于@Composer注解的一点知识笔记

最新因为一些原因&#xff0c;开始重新学习Android及kotlin编程&#xff0c;也觉得可以顺带记录下这个过程中的一些知识点&#xff0c;也可以用作日后自己查找复习。 Composable 注解在 Android 开发中的使用 Composable 是 Jetpack Compose&#xff08;Android 的现代声明式…...

【排队论】Probabilistic Forecasts of Bike-Sharing Systems for Journey Planning

Probabilistic Forecasts of Bike-Sharing Systems forJourney Planning abstract 我们研究了对共享单车系统&#xff08;BSS&#xff09;车站未来自行车可用性进行预测的问题。这是相关的&#xff0c;以便提出建议&#xff0c;保证用户能够进行旅行的概率足够高。为此&#x…...

大数据平台简介

一、分布式系统基础架构 &#xff08;一&#xff09;定义与核心特征 分布式系统是由多台计算机&#xff08;节点&#xff09;通过网络协作组成的系统&#xff0c;对外表现为一个统一整体。其核心特征包括&#xff1a; 去中心化&#xff1a;节点平等或分角色协作&#xff08;如…...

加一:从简单问题到复杂边界的深度思考

加一&#xff1a;从简单问题到复杂边界的深度思考 引言 在算法世界里&#xff0c;有些问题看似简单&#xff0c;实则暗藏玄机&#xff0c;其中“加一”问题就是一个典型例子。所谓“加一”&#xff0c;通常指的是给一个由数字组成的数组表示的整数加一&#xff0c;这听起来简…...

高精度算法(加、减、乘、除、阶乘和)​

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 唯有主动付出&#xff0c;才有丰富的果…...

实战设计模式之备忘录模式

概述 与解释器模式、迭代器模式一样&#xff0c;备忘录模式也是一种行为设计模式。备忘录模式允许我们保存一个对象的状态&#xff0c;并在稍后恢复到这个状态。该模式非常适合于需要回滚、撤销或历史记录等功能的应用场景。通过使用备忘录模式&#xff0c;开发者可以轻松添加诸…...

keil5 µVision 升级为V5.40.0.0:增加了对STM32CubeMX作为全局生成器的支持,主要有哪些好处?

在Keil5 μVision V5.40.0.0版本中,增加了对STM32CubeMX作为全局生成器的支持,这一更新主要带来了以下三方面的提升: 开发流程整合STM32CubeMX原本就支持生成Keil项目代码,但新版本将这一集成升级为“全局生成器”级别,意味着STM32CubeMX生成的代码能直接成为Keil项目的核…...

吉尔吉斯斯坦工商会代表团赴齐河德瑞新能源汽车考察

德州齐河&#xff0c;2025年4月15日电 时中美贸易突变之际&#xff0c;乘国家一带一路之风。 展中国新能源之宏图&#xff0c;塑国贸体系之新方向。 今日上午&#xff0c;吉尔吉斯斯坦共和国工商会代表团一行三人受邀抵达济南&#xff0c;开启对德瑞新能源科技有限公司&…...

无人机在农业中的应用与挑战!

一、无人机在农业中的作用 1. 提升作业效率与降低成本 无人机在喷洒农药、播种、施肥、吊运等环节显著提升效率。例如&#xff0c;湖北秭归县使用大疆T100无人机吊运脐橙&#xff0c;单次85公斤的运输任务仅需2分钟&#xff0c;而人工需1小时&#xff0c;综合成本降低250元…...

放松大脑的方法

帮助一个人放松大脑&#xff0c;需要结合生理调节、心理技巧和环境优化。以下是一些科学有效的方法&#xff0c;涵盖即时缓解和长期习惯培养&#xff1a; 一、即时放松技巧&#xff08;快速起效&#xff09; 1. 深呼吸法&#xff08;4-7-8呼吸&#xff09; 方法&#xff1a;吸…...

QT网络拓扑图绘制实验

前言 在网络通讯中&#xff0c;我qt常用的是TCP或者UDP协议&#xff0c;就比方说TCP吧&#xff0c;一台服务器有时可能会和多台客户端相连接&#xff0c;我之前都是处理单链接情况&#xff0c;最近研究图结构的时候&#xff0c;突然就想到了这个问题。那么如何解决这个问题呢&…...

英语四级翻译题练习文章示例

大学正慢慢成为过去吗?Are universiities slowly becoming a thing of the past? 1.1900年前后&#xff0c;法国艺术家让-马克科泰接受委托绘制一组图画&#xff0c;描绘他认为的2000年人们可能过上的生活。Around 1900, the French artist Jean-Marc Cote was commissioned …...