【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…

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

融合创新科技&#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库的…

一款零依赖、跨平台的流媒体协议处理工具,支持 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;支持…

ARINC 429总线协议

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

Redis应用高频面试题

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

2024年【N2观光车和观光列车司机】及N2观光车和观光列车司机模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N2观光车和观光列车司机考前必练&#xff01;安全生产模拟考试一点通每个月更新N2观光车和观光列车司机模拟考试题题目及答案&#xff01;多做几遍&#xff0c;其实通过N2观光车和观光列车司机操作证考试很简单。 1、…

LabVIEW提高开发效率技巧----用户权限控制

在LabVIEW开发中&#xff0c;用户权限控制是一个重要的设计模块&#xff0c;尤其在多用户系统中&#xff0c;它可以确保数据安全并控制不同用户的操作权限。为了实现用户权限控制&#xff0c;可以通过角色与权限管理模块来进行设计和实施。以下将从多个角度详细说明如何在LabVI…

Sentinel 快速入门

前置推荐阅读:Sentinel 介绍-CSDN博客 前置推荐阅读&#xff1a;Nacos快速入门-CSDN博客 快速开始 欢迎来到 Sentinel 的世界&#xff01;这篇新手指南将指引您快速入门 Sentinel。 Sentinel 的使用可以分为两个部分: 核心库&#xff08;Java 客户端&#xff09;&#xff1a…

新版vs code + Vue高亮、语法自动补全插件

vs code 版本或及以上 安装以下三个插件插件 Vetur Vue语法支持。包括语法高亮、语法代码提示、语法lint检测 ESLint语法纠错 Prettier 2.左下角设置 3.进行配置 配置内容&#xff1a; {"editor.fontSize": 20,"window.zoomLevel": 1,"workben…

Windows】【DevOps】Windows Server 2022 采用WinSW 启动一个会创建新的控制台程序窗口的程序行为分析

WinSW使用参考 【Windows】【DevOps】Windows Server 2022 采用WinSW将一个控制台应用程序作为服务启动&#xff08;方便&#xff09;-CSDN博客 源码 调整ConsoleApp1程序源代码如下&#xff1a; using System; using System.Diagnostics; using System.IO; using System.R…

软件生存期和软件过程

软件生存周期 软件生存周期&#xff08;Software Life Cycle&#xff09;&#xff1a;一个软件项目从问题提出开始&#xff0c;直到软件产品最终退役&#xff08;废弃不用&#xff09;为止。 软件生存周期分为三个时期&#xff1a;计划、开发和维护 整个软件生存周期划分为多…

王爽汇编语言第三版实验3

实验任务 将下面的程序保存为t1.asm&#xff0c;将其生成可执行文件t1.exe 用Vscode编写源程序t1.asm 用脚本一键生成可执行文件t1.exe 成功运行 查看资源管理器&#xff0c;成功生成T1.obj与t1.exe文件‘ 用debug跟踪t1.exe的执行过程&#xff0c;写出每一步执行后&#xff…

大模型生图安全疫苗注入——进阶解决方案与系统优化(DataWhale组队学习)

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;上篇博客中&#xff0c;我们基于DataWhale 2024年10月大模型生图安全疫苗注入赛道的任务&#xff0c;介绍了攻击与防御的基本策略&#xff0c;如通过上下文稀释法、隐喻替换等绕过检测机制&#xff0c;并提出了多…