【Linux】深入 Linux 进程等待机制:阻塞与非阻塞的奥秘

🌈个人主页:Yui_
🌈Linux专栏:Linux
🌈C语言笔记专栏:C语言笔记
🌈数据结构专栏:数据结构
🌈C++专栏:C++

文章目录

  • 1. 为什么需要进行进程等待
  • 2. 进程等待的方法
    • 2.1 wait方法
    • 2.2 waitpid方法
    • 2.3 获取子进程status
    • 2.4 进程的堵塞等待方式
    • 2.5 进程的非堵塞等待方法
  • 3.解释堵塞与非堵塞

1. 为什么需要进行进程等待

进程等待是多进程编程中至关重要的一部分,主要原因是为了让父进程正确管理子进程生命周期并避免各种问题。

  • 进行资源回收,当子进程结束后,操作系统不会立即释放与该进程相关的所有资源,需要父进程来获取子进程的终止状态,并释放这些资源。
  • 避免僵尸进程,虽然子进程已经结束运行,但是它在进程中仍然回保留占位条目,需要父进程回收。
  • 获取子进程的退出状态,用来判断子进程是否成功执行完成任务

2. 进程等待的方法

2.1 wait方法

头文件

#include <sys/types.h>
#include <sys/swit.h>

语法格式

pid_t wait(int*status);

放回值:

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

参数:

输出型参数,获取子进程的退出状态,不甘心则可以设置为NULL

测试代码:

#include <stdio.h>                                               
#include <unistd.h>                                              
#include <sys/types.h>                                           
#include <stdlib.h>                                             
#include <sys/wait.h>                                           
int main()
{pid_t id = fork();if (id < 0){perror("fork error");exit(-1);//错误情况                                               }if (id == 0){//child process                                          int cnt = 5;while (cnt--){printf("i am a child process pid:%d\n", getpid());;sleep(1);}exit(0);//process exit                                   }sleep(10);//wait child process                               printf("i am a father pid:%d\n", getpid());pid_t ret = wait(NULL);if (ret > 0) printf("father wait:%d,success\n", ret);else ("father wait failed\n");sleep(10);return 0;
}

查看进程状态:

ubuntu@VM-20-9-ubuntu:~/processWait$ while :; do ps axj | head -1 && ps axj | grep process| grep -v grep; sleep 1; echo "#######################################"; donePPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 Z+    1000   0:00 [process] <defunct>
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 Z+    1000   0:00 [process] <defunct>
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 Z+    1000   0:00 [process] <defunct>
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 Z+    1000   0:00 [process] <defunct>
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process668279  668280  668279  651091 pts/0     668279 Z+    1000   0:00 [process] <defunct>
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND651091  668279  668279  651091 pts/0     668279 S+    1000   0:00 ./process
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
#######################################PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND

查看上面的情况,我们可以发现,在中间有段时间子进程进入了僵尸状态,后来就被父进程给回收了。

2.2 waitpid方法

头文件:

#include <sys/types.h>
#include <sys/swit.h>

语法格式:

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

返回值:

当正常放回的时候waitpid返回搜集到的子进程进程ID
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0。
如果调用中出错,则返回-1,这时error会被设置成相对应的值以指示错误所在。

参数:

pid:pid=-1,等待任意一个子进程,与wait等效。pid>0,等待其进程ID与pid相等的子进程。
status:WIFEXITED(status):如果正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXISTATUS(status):如果WIFEXIED非0,提取子进程退出码。(查看进程退出码)
options:WNOHANG:如果pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待,如果正常结束,则返回该子进程的ID。
  • 如果子进程已经退出,调用wait/waitpid会立即返回,并且释放资源,获取子进程退出信息。
  • 如果任意时刻调用wait/waitpid,子进程存在且正常运行,则可能阻塞。
  • 如果不存在该进程,则立即出错放回。

2.3 获取子进程status

  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 如果不传递NULL,操作系统会会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整型来看,应该当作位图来看待。

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if(id<0){perror("fork fail");exit(1);}if(id == 0){//childprintf("i am a child pid:%d\n",getpid());sleep(20);exit(10);}else{//fatherint status;int ret = wait(&status);if(ret>0&&(status&0x7F)==0){//normal exitprintf("child exit code:%d\n",(status>>8)&0xFF);}else if(ret>0){printf("sig code:%d\n",status&0x7F);}}return 0;
}

正常退出会打印:child exit code:10
运行过程中被kill掉:sig code:9

2.4 进程的堵塞等待方式

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>int main()
{pid_t id = fork();if(id < 0){perror("fork fail");exit(1);}else if(id == 0){//childprintf("i am a child,pid is:%d\n",getpid());sleep(5);exit(257);}else{	//fatherint status = 0;pid_t ret = waitpid(-1,&status,0);//阻塞等待printf("This is test for wait\n");if(WIFEXITED(status)&&ret == id){printf("wait child 5s success,child return code is:%d\n",WEXITSTATUS(status));}else{printf("wait child failed,return\n");return 1;}}return 0;
}

执行过程:
因为阻塞等待的缘故,在子进程结束前父进程都不会执行下一条语句。会一直卡在pid_t ret = waitpid(-1,&status,0);者句语句。
执行结果:

i am a child,pid is:701810
This is test for wait
wait child 5s success,child return code is:1

提问:为什么会放回1呢
回答:
在上面的图中,我们得知了但程序正常退出后,其退出状态存储在低8位中,而257的二进制位为0001 0000 0001,会被截断为1

2.5 进程的非堵塞等待方法

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>int main()
{pid_t id = fork();if(id < 0){perror("fork fail");exit(1);}else if(id == 0){//childprintf("i am a child,pid is:%d\n",getpid());sleep(5);exit(1);}else{	//fatherint status = 0;pid_t ret = 0;do{ret = waitpid(-1,&status,WNOHANG);//非阻塞等待if(ret == 0){printf("child is running\n");}sleep(1);}while(ret == 0);if(WIFEXITED(status)&&ret == id){printf("wait child 5s success,child return code is:%d\n",WEXITSTATUS(status));}else{printf("wait child failed,return\n");return 1;}}return 0;
}

执行结果:

child is running
i am a child,pid is:711095
child is running
child is running
child is running
child is running
wait child 5s success,child return code is:1

从这两段代码大家肯定可以分的清楚堵塞和非堵塞的区别了吧。就是还不理解,下面我在来一个例子相信大家一定就没有问题了。

3.解释堵塞与非堵塞

  • 阻塞场景:打电话等朋友接听
    • 你拨打朋友的电话,直到朋友接通之前你什么都做不了。这就像阻塞调用,你必须等着事情完成。
  • 非阻塞场景:发消息等待回复
    • 你给朋友发了个消息,等他们回你。你不用一直盯着手机看,而是可以去做别的事情,等收到消息后再查看。这就像非阻塞调用,你不需要等着完成才能做其他事情。

就是如此,感谢观看本篇文文章,提前感谢大家的点赞与收藏~

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

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

相关文章

spring底层原理

本文参考黑马程序员的spring底层讲解&#xff0c;想要更详细的可以去看视频。 另外文章会每日更新&#xff0c;大概持续1个月&#xff01;&#xff01;&#xff01;每天更新一讲 这部分比较抽象&#xff0c;要经常复习&#xff01;&#xff01;&#xff01; 一、BeanFactory与A…

【JPCS独立出版 | 福州大学主办 | 有确定的ISSN号】第三届可再生能源与电气科技国际学术会议(ICREET 2024)

第三届可再生能源与电气科技国际学术会议&#xff08;ICREET 2024&#xff09; 2024 3rd International Conference on Renewable Energy and Electrical Technology ICREET 2024已成功申请JPCS - Journal of Physics: Conference Series (ISSN:1742-6596) 独立出版&#xf…

【算法日记】力扣239 滑动窗口最大值

题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a;nums [1,3,-1,-3,5,3,6,…

引领智慧文旅新纪元,开启未来旅游新境界

融合创新科技&#xff0c;重塑旅游体验&#xff0c;智慧文旅项目定义旅游新未来 在全球化的浪潮中&#xff0c;旅游已成为连接世界的重要纽带。智慧文旅项目&#xff0c;不仅仅是一次技术的革新&#xff0c;更是对旅游行业未来发展的一次深刻思考。信鸥科技通过运用云计算、大数…

Vue3动态组件原来是这样

什么是Vue3动态组件 在Vue3中&#xff0c;动态组件简单来说就是根据不同的条件进行不同组件的渲染&#xff0c;可以联想一下在前端中常用到的动态样式 基本使用 在Vue3中&#xff0c;动态组件的使用也是非常简单的&#xff0c;只需要使用<component>标签&#xff0c;并…

WPFDeveloper正式版发布

WPFDeveloper WPFDeveloper一个基于WPF自定义高级控件的WPF开发人员UI库&#xff0c;它提供了众多的自定义控件。 该项目的创建者和主要维护者是现役微软MVP 闫驚鏵: https://github.com/yanjinhuagood 该项目还有众多的维护者&#xff0c;详情可以访问github上的README&…

Redis 高可用:从主从到集群的全面解析

目录 一、主从复制 (基础)1. 同步复制a. 全量数据同步b. 增量数据同步c. 可能带来的数据不一致 2. 环形缓冲区a. 动态调整槽位 3. runid4. 主从复制解决单点故障a. 单点故障b. 可用性问题 5. 注意事项a. Replica 主动向 Master 建立连接b. Replica 主动向 Master 拉取数据 二、…

STM32传感器模块编程实践(八) HX711压力传感器称重模块简介及驱动源码

文章目录 一.概要二.HX711主要技术指标三.HX711模块参考原理图四.模块接线说明五.模块工作原理介绍六.模块通讯协议介绍七.STM32单片机与HX711模块实现重量测量实验1.硬件准备2.软件工程3.软件主要代码4.实验效果 八.小结 一.概要 电子秤是将检测与转换技术、计算机技术、信息…

Python网络爬虫从入门到实战

目录 引言 一、网络爬虫的概念 二、 网络爬虫的基本工作流程 &#xff08;一&#xff09;过程&#xff1a; &#xff08;二&#xff09;安装requests模块和beautifulsoup4模块 &#xff08;三&#xff09;requests库的使用 1、requests库的基本介绍 2、导入requests库的…

Linux文件权限基础与管理指南

在Linux操作系统中&#xff0c;文件权限是一个至关重要的概念&#xff0c;它决定了用户对文件和目录的访问控制。理解文件权限不仅有助于保护系统安全&#xff0c;还能提高文件管理的效率。本文将介绍Linux文件权限的基本概念、类型以及如何管理这些权限&#xff0c;并提供更多…

Cisco Nexus N93108转换模式for Nxos to ACI mode失败案例

到货6台 Nexus 93108TC-FX switch 到货时系统为NXOS 由于我们是ACI环境 &#xff0c;所以需要将其转换为ACI 镜像&#xff0c;否则是无法注册到APIC上的。 前5台的操作都很顺利&#xff0c;按以下步骤操作完重启就完成了。 1 确认bootflash中有ACI的镜像 switch# dir4096 …

一款零依赖、跨平台的流媒体协议处理工具,支持 RTSP、WebRTC、RTMP 等视频流协议的处理

大家好&#xff0c;今天给大家分享一款功能强大的流媒体协议处理工具go2rtc&#xff0c;支持多种协议和操作系统&#xff0c;具有零依赖、零配置、低延迟等特点。 项目介绍 go2rtc可以从各种来源获取流&#xff0c;包括 RTSP、WebRTC、HomeKit、FFmpeg、RTMP 等&#xff0c;并…

学习文档10/16

MySQL 字符集&#xff1a; MySQL 支持很多种字符集的方式&#xff0c;比如 GB2312、GBK、BIG5、多种 Unicode 字符集&#xff08;UTF-8 编码、UTF-16 编码、UCS-2 编码、UTF-32 编码等等&#xff09;。 查看支持的字符集 你可以通过 SHOW CHARSET 命令来查看&#xff0c;支持…

java HttpURLConnection传递键值对参数,表单参数

当表头设置参数类型为这个的时候&#xff0c; conn.setRequestProperty(“Content-Type”,“application/x-www-form-urlencoded”); 如果参数用的是jsonstring的话&#xff0c;在请求中&#xff0c;参数会都跑到key中&#xff0c;而且不会自动识别key和value&#xff1b; Str…

SpringBoot框架的车辆管理自动化解决方案

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

ARINC 429总线协议

一、概述 ARINC 是美国航空无线电公司英文字头的缩写&#xff0c; 该公司1977年7月21日出版了“ARINC 429规范”一书&#xff0c;429规范就是飞机电子系统之间数字式数据传输的标准格式&#xff0c;在飞机上使用429总线的电子设备均应遵守这个规范&#xff0c;这样才能保证电子…

Linux C语言 进程详解——fork()/wait()/waitpid()

一、fork()函数 1. 头文件 #include<unistd.h> #include<sys/types.h>2. 函数原型及功能介绍函数原型pid_t fork( void);(pid_t 是一个宏定义,其实质是int 被定义在#includesys/types.h>中)返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进…

Redis应用高频面试题

Redis 作为一个高性能的分布式缓存系统,广泛应用于后端开发中,因此在后端研发面试中,关于 Redis 的问题十分常见。 本文整理了30个常见的 Redis 面试题目,涵盖了 Redis 的源码、数据结构、原理、集群模式等方面的知识,并附上简要的回答,帮助大家更好地准备相关的面试。 …

2024 复健记

2024 复健记 OI生涯结束两年了&#xff08;六年OI一场空&#xff0c;梦里花落知多少&#xff09; 这两天闲着无事翻了翻自己的CSDN&#xff0c;发现上一篇文章已经是两年之前了。那时候退役&#xff0c;虽然不知道梦应归于何处&#xff0c;但依旧梦里栩然蝴蝶、一身轻。如今忆…

独孤思维:图书电商做亏本了怎么弥补

01 昨天有个人问我&#xff0c;我做cps拉新。 拉了多少人&#xff0c;奖励了我免费星球的名额。 这个是博主个人行为&#xff0c;而且也是阶段性奖励&#xff0c;现在没有了。 其实这些都不是关键。 很多人喜欢问一些无聊的问题&#xff0c;只想要结果。 却从来不去探究自…