【进程等待】waitpid的参数pid | status的位图位操作WIFEXITEDWEXITSTATUS宏
目录
waitpid
pid
status
status位图
status按位操作
输入型参数和输入型参数
宏WIFEXITED&WEXITSTATUS
options&非阻塞等待
上篇进程等待我们介绍到怎样去进程等待。我们介绍了wait函数&阻塞等待。本篇我们将介绍waitpid函数的参数pid和status。
waitpid
- man 2 waitpid
- 等待一个进程的状态发生变化
- pit_t pid是父进程等待的子进程的pid,情况有3种,这里介绍两种情况。
- int *status是NULL
- int options是0
- 先把后面两个参数设置为NULL和0
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:
- WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。
waitpid是一个在Unix和类Unix系统(如Linux)中常用的系统调用,用于等待一个或多个子进程的状态改变。与wait系统调用相比,waitpid提供了更多的灵活性,因为它允许你指定要等待的子进程的PID(进程ID),并可以设置等待的模式(阻塞或非阻塞)。以下是
waitpid函数的原型和参数详解:
pid_t waitpid(pid_t pid, int *status, int options);
pid:这是一个整数,用于指定要等待的子进程的PID。其取值有以下几种情况:
pid > 0:等待指定PID为pid的子进程。pid = 0:等待当前进程组中的任何子进程。pid = -1:等待任何子进程,与wait函数的功能相同。pid < -1:等待组ID为-pid的任意子进程。status:这是一个指向整数的指针,用于存储子进程的退出状态。如果不需要这些信息,可以将此参数设置为NULL。options:这是一个位掩码,用于修改waitpid的行为。常见的选项有:
WNOHANG:使waitpid调用变为非阻塞。如果没有子进程满足条件,waitpid会立即返回。WUNTRACED:当子进程被停止时(而不是退出时),也返回它的状态。这通常与跟踪被调试的子进程有关。WCONTINUED:当被停止的子进程恢复时,返回它的状态。
waitpid的返回值有以下几种情况:
- 如果成功,返回收集到的子进程的PID。
- 如果设置了
WNOHANG选项并且没有子进程满足条件,返回0。- 如果在调用中出现错误,返回-1,并设置全局变量
errno以指示错误。
waitpid是一个非常有用的工具,允许你更精细地控制和管理你的子进程。

pid
- 这样设置waitpid的参数,waitpid(-1,NULL,0)和 wait(NULL)的功能一致
- pid = -1表示等待任何一个子进程的退出
- pid > 0表示等待指定的一个子进程的退出
- pid为错误数字。wait fail !(只要pid不输入错误❌一般父进程都不会等待失败)
- fork返回值
- 0是子进程执行
- >0返回的是子进程的pid 是父进程执行(id是子进程的pid数值)
pid:这是一个整数,用于指定要等待的子进程的PID。其取值有以下几种情况:
pid > 0:等待指定PID为pid的子进程。pid = 0:等待当前进程组中的任何子进程。pid = -1:等待任何子进程,与wait函数的功能相同。pid < -1:等待组ID为-pid的任意子进程。
myprocess.c 1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 #include<stdlib.h>5 #include<sys/types.h>6 #include<sys/wait.h>7 8 void ChildRun()9 {10 int cnt = 5;11 while(cnt--)12 {13 printf("I am child,pid: %d,ppid: %d,cnt: %d\n",getpid(),getppid() ,cnt);14 sleep(1);15 }16 }17 18 int main()19 {20 printf("I am father,pid: %d,ppid: %d\n",getpid(),getppid());//父进> 程21 pid_t id = fork(); 22 if(id == 0)//child子进程23 {24 //子进程循环运行25 ChildRun();26 printf("Child quit...\n");27 exit(0);//终止进程,子进程直接僵尸28 }29 //father30 //父进程,父进程在子进程运行期间5ms一直在等待....31 //pid_t rid = wait(NULL); 32 pid_t rid = waitpid(id,NULL,0);33 if(rid > 0)34 {35 printf("wait success,rid: %d\n",rid);36 } 37 sleep(3);38 printf("father quit ... \n");39 }
【错误的pid演示】
//father31 //父进程,父进程在子进程运行期间5ms一直在等待.... 32 pid_t rid = waitpid(id+1 , NULL , 0);33 if(rid > 0)34 {35 printf("wait success,rid: %d\n",rid);36 }37 else38 {39 printf("wait fail !\n");40 }41 sleep(3);42 printf("father quit ... \n");

status
status:这是一个指向整数的指针,用于存储子进程的退出状态。如果不需要这些信息,可以将此参数设置为NULL。
- int *status表示通过等待获取子进程的退出信息。(❗前面的进程终止已知进程终止的退出信息表示退出码&退出信号)
- 父进程通过waitpid等待子进程,通过第二个参数就可以拿到子进程的退出信息(status是输出型参数)
- 当然也存在父进程不关心子进程的退出信息,&status直接置为NULL即可。(等待是必须的,但是获取子进程的退出信息不是必须的)
- status不能简单的当作整形来看待,可以当作位图来看待,存在特定的格式。
- status是输出型参数。
- status按位操作拿到退出码和退出信号。
- status通过下面两个宏拿到退出码和退出信号。
- WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
- WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码。
有人问可不可以不用waitpid传递子进程的退出信息,直接定义两个全局变量exit_code,exit_signal。在子进程退出的时候写入自己的退出信息到全局变量当中❓
- 当然不可以,全局也是数据。虽然一开始是被父子进程共享,当子进程要写入的时候,会发生写时拷贝,此刻父子进程都有一份各自的全局变量的数据,父进程是看不到的子进程写入自己的全局变量的数据。
- 所以只能通过waitpid的status参数。下面我们来仔细学习以下☞☞
status位图
怎么把子进程的退出信息(退出码和退出信号)整合成一个数字赋值给status呢❓
- wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
- 如果传递NULL,表示不关心子进程的退出状态信息。
- 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
- status不能简单的当作整形来看待,可以当作位图来看待,存在特定的格式,32比特位具体细节如下图(只研究status低16比特位)
- 32比特位只使用低16比特位
- 其中次低8位:进程退出时所对应的退出状态(退出码)
- 其中最低7位:进程退出时是否受到终止信号(退出信号)
- 第8位:暂时不考虑,后面进程信号会讲
- 所以,退出状态的取值范围是[0,255],退出信号取值范围:[0,127]
- status是以位图的形式把子进程的退出码和退出信息返回给父进程的
在Linux的
waitpid函数中,status参数是一个指向整数的指针,它用于存储子进程的退出状态信息。尽管status本身是一个整型指针,但我们更关心的是它所指向的那个整数变量的取值范围和内容。
- 这个整数变量(我们称之为
status_val)通常用于表示子进程的退出状态。在大多数情况下,我们只关心这个整数的低16位,因为高16位通常不被使用。- 正常退出:如果子进程正常退出(即调用了
exit()函数),那么status_val的低16位的高8位将保存子进程的返回值(范围是0-255)。低8位中的低7位将被设置为0,而最高位(第8位)通常被用来表示一个标志位,以区分是正常退出还是由于信号而退出。- 异常退出:如果子进程由于接收到一个信号而退出,那么
status_val的低16位的低7位将保存导致子进程退出的信号的编号(范围通常是1-127,但取决于系统和信号的具体实现)。同样,最高位(第8位)将用于表示是由于信号而退出。为了从
status_val中提取这些信息,可以使用一些宏(如WEXITSTATUS、WTERMSIG等)来进行位操作和提取。因此,
status本身并没有一个固定的取值范围,因为它只是一个指针。但它所指向的那个整数变量(status_val)的取值范围和内容则取决于子进程的退出状态。


status按位操作
我们知道子进程的退出码和退出信息被父进程调用waitpid等待时,赋值给status参数。如果我们想要在父进程里面查看详细的子进程的退出码和退出信息🆗请看下面代码。
- 正常退出:(status>>8)&0xFF
- 异常退出:status&0x7F
- 解释☞位操作专题。
//....同上18 int main()19 {20 printf("I am father,pid: %d,ppid: %d\n",getpid(),getppid());//父进程21 pid_t id = fork();22 if(id == 0)//child子进程23 {24 //子进程循环运行25 ChildRun();26 printf("Child quit...\n");27 exit(1);//终止进程,子进程直接僵尸28 }29 //father30 //父进程,父进程在子进程运行期间5ms一直在等待.... 31 int status = 0;32 pid_t rid = waitpid(id, &status, 0);33 if(rid > 0)34 {35 printf("wait success,rid: %d\n",rid);36 }37 else38 {39 printf("wait fail !\n");40 }41 sleep(3);42 printf("father quit,status: %d,code: %d,signal: %d\n",status, (status>>8)&0XFF,status&0X7F); 43 }

【kill -9 pid错误测试】

【野指针错误测试】


输入型参数和输入型参数
在函数或系统调用的参数中,我们通常区分输入型参数(Input Parameters)和输出型参数(Output Parameters)。这些参数在函数或系统调用的执行过程中扮演不同的角色。
输入型参数(Input Parameters):
- 这些参数是函数或系统调用所需的信息或数据,用于执行特定的任务或操作。
- 它们通常由调用者(Caller)提供,并在函数或系统调用内部被使用。
- 输入型参数的值在函数或系统调用执行前后不会改变(除非函数或系统调用有特定的功能去修改它们)。
- 在
waitpid函数中,pid和options是输入型参数。pid指定了要等待的子进程的PID,而options则设置了等待的行为(如阻塞或非阻塞)。输出型参数(Output Parameters):
- 这些参数用于存储函数或系统调用的结果或返回的数据。
- 它们通常在函数或系统调用执行前未定义或具有初始值,但在执行后被赋值或更新。
- 输出型参数的值在函数或系统调用执行后会被改变。
- 在
waitpid函数中,status是输出型参数。它用于存储子进程的退出状态信息,这些信息在函数执行前是未知的。总结:输入型参数是函数或系统调用所需的信息,而输出型参数则用于存储函数或系统调用的结果。在调用函数或系统调用时,正确设置输入型参数和处理输出型参数是非常重要的。
【输入型参数VS输出型参数】简而言之,输入型参数是调用者提供,输出型参数是程序赋值提供 
宏WIFEXITED&WEXITSTATUS
除了用status通过按位操作来提取子进程的退出码和退出信号,有没有其他方法❓
- status按位操作不方便,介绍两个宏。(本质上就是status按位操作封装的)
- WIFEXITED(status): 若为正常终止子进程返回状态,则为真。查看进程是否是正常退出
- WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。查看进程的退出码
- WIFEXITED:W:wait IF:if EXITED:exited(等待退出)
- WEXITSTATUS:W:wait EXIT:exit STATUS:status(等待退出状态)
- 本质是:检查退出信号sign位也就是status的低7位是否位0,为0则是正常退出。非0则是异常退出。若是正常退出则若用户愿意可以用WEXITSTATUS查看退出码。
- ❗可以用这两个宏来判断是否退出为正常。
1: myprocess.c1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h>4 #include<stdlib.h>5 #include<sys/types.h>6 #include<sys/wait.h>7 8 void ChildRun()9 { 10 int cnt = 5;11 while(cnt--)12 {13 printf("I am child,pid: %d,ppid: %d,cnt: %d\n",getpid(),getppid(),cnt);14 sleep(1);15 }16 }17 18 int main()19 {20 printf("I am father,pid: %d,ppid: %d\n",getpid(),getppid());//父进程21 pid_t id = fork();22 if(id == 0)//child子进程23 {24 //子进程循环运行25 ChildRun();26 printf("Child quit...\n");27 exit(1);//终止进程,子进程直接僵尸28 }29 //father30 //父进程,父进程在子进程运行期间5ms一直在等待.... 31 int status = 0;32 pid_t rid = waitpid(id, &status, 0);33 if(rid > 0)34 {35 if(WIFEXITED(status))36 {37 printf("child quit normal,child exit code: %d\n",WEXITSTATUS(status));38 }39 else40 {41 printf("child quit unnormal!\n");42 }43 printf("wait success,rid: %d\n",rid); 44 }45 else46 {47 printf("wait fail !\n");48 }49 sleep(3);50 //printf("father quit,status: %d,code: %d,signal: %d\n",status,(status>>8)&0XFF,status&0X7F);51 }

options&非阻塞等待
前面讲到在子进程运行期间,父进程一直在等待,能不能干点别的事情❓
options:这是一个位掩码,用于修改waitpid的行为。常见的选项有:
WNOHANG:使waitpid调用变为非阻塞。如果没有子进程满足条件,waitpid会立即返回。WUNTRACED:当子进程被停止时(而不是退出时),也返回它的状态。这通常与跟踪被调试的子进程有关。WCONTINUED:当被停止的子进程恢复时,返回它的状态。
🙂感谢大家的阅读,若有错误和不足,欢迎指正。下篇阻塞等待和非阻塞等待以及waitpid的最后一个参数。
相关文章:
【进程等待】waitpid的参数pid | status的位图位操作WIFEXITEDWEXITSTATUS宏
目录 waitpid pid status status位图 status按位操作 输入型参数和输入型参数 宏WIFEXITED&WEXITSTATUS options&非阻塞等待 上篇进程等待我们介绍到怎样去进程等待。我们介绍了wait函数&阻塞等待。本篇我们将介绍waitpid函数的参数pid和status。 waitp…...
unity---常用API
1. Vector3:结构体由x、y、z这3个数值组成,表示一个向量 magnitude变量返回该向量的长度normalized变量返回 magnitude 为 1 时的该向量zero静态变量Vector3(0, 0, 0)one静态变量Vector3(1, 1, 1)forward静态变量Vector3(0, 0, 1)back静态变量Vector3(0…...
设计模式: 模板模式
目录 一,模板模式 二,特点 三,组成部分 四,实现步骤 五,案例 一,模板模式 模板模式(Template Pattern)是一种行为型设计模式,它在超类中定义了一个算法的骨架&#…...
[虚拟机+单机]梦幻契约H5修复版_附GM工具
本教程仅限学习使用,禁止商用,一切后果与本人无关,此声明具有法律效应!!!! 教程是本人亲自搭建成功的,绝对是完整可运行的,踩过的坑都给你们填上了 视频演示 [虚拟机单…...
头文件相互包含 前向声明
当两个类需要相互访问对方的成员或方法时,通常意味着它们之间存在某种依赖关系。这种依赖关系可能源于类的设计或功能需求。以下是一个简单的例子,展示了当两个类需要相互访问对方成员或方法时,如何使用包含对方头文件的方式来解决循环包含的…...
七款好用的上网行为管理软件推荐 |有没有好用的上网行为管理系统
七款好用的上网行为管理软件推荐 |有没有好用的上网行为管理系统 员工上班刷视频! 员工上班炒股! 员工上班干副业! 碰见这种情况怎么办?当然是用电脑监控软件来监视员工的一举一动了,那么这样的软件有哪些呢&#…...
centos7-bcc 安装
检查 内核信息 确保安装的kernel-dev 和内核版本一致!!! rpm -qa|grep kernel kernel-tools-3.10.0-1160.92.1.el7.x86_64 kernel-devel-3.10.0-1160.92.1.el7.x86_64 kernel-headers-3.10.0-1160.92.1.el7.x86_64 kernel-3.10.0-1160.92.1.el7.x86_64 kernel-tools-libs-3.1…...
5.06号模拟前端面试8问
5.06号模拟前端面试8问 1.promise如何实现then处理 在JavaScript中,Promise 是一个代表异步操作最终完成或失败的对象。它有三种状态:pending(等待),fulfilled(完成),rejected&…...
解读Inscode AI:开启代码智能化的新时代
导语: 近年来,人工智能技术的迅猛发展已经深刻地影响着各个行业,而在软件开发领域,Inscode AI的出现无疑将给代码智能化带来一场革命。本文将为大家解读Inscode AI的特点和应用,探索其如何改变我们的软件开发方式。 一…...
快速了解Vuex
Vuex Vuex使用Vuex Vuex 📌vuex 是一个专为 Vue.js 应用程序开发的状态管理库 📌vuex 可以在多个组件之间共享数据,并且共享的数据是响应式的,即数据的变更能及时渲染到模板 📌vuex 采用集中式存储管理所有组件的状态…...
vue管理系统导航中添加新的iconfont的图标
1.在官网上将需要的图标,加入项目中,下载 2.下载的压缩包中,可以选择这两个,复制到项目目录中 3.如果和之前的iconfont有重复,那么就重新命名 4.将这里的.ttf文件,也重命名为自己的 5.在main文件中导入 6.在…...
Docker的介绍及与传统虚拟化技术的区别
Docker是一个开源的应用容器引擎,它使得开发者可以将应用及其依赖包打包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上。Docker基于Go语言开发,它的出现极大地简化了应用程序的部署、管理和扩展。 以下是Docker…...
06.Git远程仓库
Git远程仓库 #仓库种类,举例说明 github gitlab gitee #以这个仓库为例子操作登录码云 https://gitee.com/projects/new 创建仓库 选择ssh方式 需要配置ssh公钥 在系统上获取公钥输入命令:ssh-keygen 查看文件,复制公钥信息内…...
Anaconda安装和深度学习环境的安装(TensorFlow、Pytorch)
换了新电脑,重新装一下anaconda这些编程环境。好久没装过了,自己也需要查查资料,然后记录一下,分享给别人。 目标,三个环境:1.anaconda基础环境(包含xgboost和lightgbm),…...
元素设置 flex:1,但是会被内部长单词宽度超出拉伸
初始布局如上图,left中是代码编辑器,实际上是个文本域,当输入长文本过长时,left宽度会被拉伸。 右侧容器被挤压。 解决方案:width:0; .left{flex:1; width:0} 当输入长文本过长时,…...
win11 安装oracle11g详细流程及问题总结
1.安装包下载地址 本案例操作系统, Oracle 11g下载-Oracle 11g 64位/32位下载官方版(附详细的安装图解教程) - 多多软件站多多为大家免费提供Oracle 11g下载,包含64位/32位官方版本,并附详细的Oracle 11g安装图解教程,同时希望能…...
自我模拟面试
在面试中,你如何面对面试官呢? 我认为,对于面试官提出的问题,如果你不会,那就是不会。你的思考过程,实际上就是将你平时所学的,所了解的,在脑海中进行一次复习,就像当别…...
头歌java面向对象基础
第一关类的定义 package step1;// ---------------------Begin------------------------ public class Student{String name"李四";int age18;public void speak(){System.out.println("我爱学习");} }// ---------------------End----------------------…...
PMP课程知识点很多,无法入手,该如何学习?
回顾整个学习过程,我花费了不少时间,但也学到了系统的项目管理知识,考试结果也让我感到满意。在学习过程中,我认为以下几点非常重要: 1、需要对课本进行整体阅读,以便对内容有一个整体印象; 2…...
隔离流量优化网络传输
不要将长流和短突发流(或者大象流和老鼠流)混部在一起,我建议用切片或虚通道将它们在全链路范围彻底隔离,而不仅仅在交换机上配合着大肆宣讲的高端包分类算法配置一些排队调度。 也不必扯泊松到达,帕累托分布,这些概念在论文建模…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
