【Linux探索学习】第十八弹——进程等待:深入解析操作系统中的进程等待机制

Linux学习笔记:https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在Linux操作系统中,进程是资源的管理和执行单元,每个进程都有其自己的生命周期。在进程的执行过程中,进程可能需要等待一些资源或事件的发生,例如等待I/O操作完成、等待信号、等待其他进程的结束等,这些都叫做进程等待。这些我们在前面讲进程状态的时候基本上都提到过,今天我们重点来讲解父进程等待子进程这类等待其它进程结束的问题

目录

1. 父进程为什么要等待子进程

2. 父进程等待子进程的常用函数

3. wait() 和 waitpid() 函数详解

3.1 wait()

3.2 waitpid()

4. 使用 SIGCHLD 信号等待子进程

5. 僵尸进程与避免方法

6. 总结


1. 父进程为什么要等待子进程

在前面上篇我们已经讲过僵尸状态的问题,子进程在执行结束后,如果父进程不及时进行接受处理,子进程就会进入僵尸状态,进入僵尸状态后,从而造成内存泄漏,而且kill -9信号也不能进行处理,同时我们的父进程也需要通过进程退出的方式来回收子进程资源,获取子进程退出信息,所以说进程等待十分有必要。


2. 父进程等待子进程的常用函数

Linux 提供了多个函数用于父进程等待子进程的结束:

函数名描述
wait()阻塞父进程,直到任一子进程退出,返回退出的子进程 PID。
waitpid()更灵活的等待函数,可选择等待特定子进程,支持非阻塞模式。
waitid()类似于 waitpid(),但功能更强大,支持更详细的选项。
signal()sigaction()注册 SIGCHLD 信号处理函数,用于非阻塞地获取子进程状态。

这四个函数中我们主要用到的是前两个函数,所以我们下面对前两个函数进行详细讲解


3. wait()waitpid() 函数详解

3.1 wait()

wait() 是最简单的等待子进程的函数,用法如下:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程printf("Child process running...\n");sleep(3);  // 模拟一些操作printf("Child process exiting...\n");exit(42);  // 退出码为 42} else {// 父进程int status;pid_t child_pid = wait(&status);  // 等待任意子进程结束if (WIFEXITED(status)) {  // 检查子进程是否正常退出printf("Child process %d exited with status %d\n", child_pid, WEXITSTATUS(status));}}return 0;
}

输出示例:

Child process running...
Child process exiting...
Child process 12345 exited with status 42

说明:

  • wait(&status) 阻塞父进程,直到有子进程退出。
  • 使用宏 WIFEXITEDWEXITSTATUS 分别检查子进程是否正常退出及其退出码。

补充:

  • 上面的例子中子进程只有一个,但有些时候我们可能有多个子进程,这个时候系统采用的是循环等待的方法来回收每一个子进程
  • 父进程在回收子进程时是随机的,也就是说当我们有多个子进程执行结束的时候,父进程先回收哪个子进程并不是确定的,是随机的,这也就是我们上面采用循环等待的原因
  • 循环等待的具体方法会在文章最后面的总结图里面给出示例

3.2 waitpid()

waitpid() 是更灵活的等待函数,支持:

  • 等待特定的子进程。
  • 非阻塞模式。

函数原型:

pid_t waitpid(pid_t pid, int *status, int options);
参数描述
pid

指定子进程的 PID,若为 -1 等待任意子进程,与pid等效;若大于1则等待其进程ID与pid相同的子进程

status存储子进程的退出状态。
options控制等待行为(如 WNOHANG 表示非阻塞)。

我们先对上面的表格做一个小补充:

参数option作用是控制等待行为,常见的等待方式主要有两种:阻塞等待和非阻塞等待

阻塞等待的意思就是在我们父进程等待子进程的过程中会进入阻塞状态,不会做其它的事情,直到子进程运行结束后再继续,而非阻塞等待则是不同的方式,非阻塞状态的父进程会在运行的过程中不断询问查看子进程的运行情况,当子进程运行结束时,会将结果反馈给父进程,但是在这个过程中父进程并不会停下来,它还会继续自己的执行

示例代码:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>int main() {pid_t pid1 = fork();if (pid1 == 0) {// 第一个子进程printf("Child 1 running...\n");sleep(2);printf("Child 1 exiting...\n");exit(1);}pid_t pid2 = fork();if (pid2 == 0) {// 第二个子进程printf("Child 2 running...\n");sleep(4);printf("Child 2 exiting...\n");exit(2);}// 父进程int status;pid_t child_pid;while ((child_pid = waitpid(-1, &status, 0)) > 0) {  // 等待所有子进程if (WIFEXITED(status)) {printf("Child %d exited with status %d\n", child_pid, WEXITSTATUS(status));}}return 0;
}

输出示例:

Child 1 running...
Child 2 running...
Child 1 exiting...
Child 12345 exited with status 1
Child 2 exiting...
Child 12346 exited with status 2


4. 使用 SIGCHLD 信号等待子进程

信号的知识我们在前面还没进行讲解,这里还是了解为主,感兴趣的可以看看,不懂的地方可以去搜一下:

SIGCHLD 信号在子进程状态发生变化时(如退出)发送给父进程。父进程可以注册信号处理函数来处理此信号。

代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>void sigchld_handler(int sig) {int status;pid_t pid = wait(&status);  // 获取退出的子进程信息if (pid > 0 && WIFEXITED(status)) {printf("Child %d exited with status %d\n", pid, WEXITSTATUS(status));}
}int main() {signal(SIGCHLD, sigchld_handler);  // 注册信号处理器pid_t pid = fork();if (pid == 0) {// 子进程printf("Child process running...\n");sleep(3);printf("Child process exiting...\n");exit(42);}// 父进程printf("Parent process doing other work...\n");while (1) {  // 模拟父进程的其他工作sleep(1);}return 0;
}

输出示例:

Parent process doing other work...
Child process running...
Child process exiting...
Child 12345 exited with status 42


5. 僵尸进程与避免方法

文章开头我们就已经讲过僵尸进程了,通过上面对进程等待的学习,再来看一下僵尸进程的概念,看看能不能加深理解

僵尸进程(Zombie Process) 是指子进程退出后,其退出信息尚未被父进程读取的状态。虽然僵尸进程不会占用CPU,但其占用的进程表项资源有限。

避免僵尸进程的方法:

  1. 确保父进程读取子进程状态:使用 wait()waitpid()
  2. 忽略 SIGCHLD 信号:通过 signal(SIGCHLD, SIG_IGN) 忽略信号。
  3. 使用守护进程(init 进程回收子进程):如果父进程终止,init 进程会自动接管并回收子进程。

6. 总结

父进程等待子进程是进程管理中的关键机制。在实际应用中:

  • 简单的任务可以使用 wait()
  • 更复杂的需求(如非阻塞、多子进程等待)推荐使用 waitpid()
  • 实时应用可以结合 SIGCHLD 信号处理。

合理地使用这些机制,不仅可以有效管理资源,还能避免僵尸进程的问题,提升程序的健壮性和运行效率。

本篇笔记:


感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!

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

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

相关文章

大数据技术Kafka详解 ② | Kafka基础与架构介绍

目录 1、kafka的基本介绍 2、kafka的好处 3、分布式发布与订阅系统 4、kafka的主要应用场景 4.1、指标分析 4.2、日志聚合解决方法 4.3、流式处理 5、kafka架构 6、kafka主要组件 6.1、producer(生产者) 6.2、topic(主题) 6.3、partition(分区) 6.4、consumer(消费…

嵌入式Linux之wifi配网脚本分析

嵌入式Linux系统,一般都支持wifi联网,可以通过sh脚本或其它语言代码编程来实现wifi联网。 本篇来介绍一种通过sh脚本来配置wifi的脚本执行原理。 1 sh脚本wifi联网介绍 这里以飞凌开发板中的wifi启动脚本为例来介绍。 在飞凌开发板的串口中,执行如下命令(调用fltest_wif…

如何通过 JWT 来解决登录认证问题

1. 问题引入 在登录功能的实现中 传统思路&#xff1a; 登录页面时把用户名和密码提交给服务器服务器验证用户名和密码&#xff0c;并把检验结果返回给后端如果密码正确&#xff0c;则在服务器端创建 session&#xff0c;通过 cookie 把 session id 返回给浏览器 但是正常情…

【Linux】文件操作的艺术——从基础到精通

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长&#xff0c;行则将至 目录 &#x1f4da;前言&#xff1a;一切皆文件 &#x1f4da;一、C语言的文件接口 &#x1f4d6;1.文件打…

JAVA |日常开发中常见问题归纳讲解

JAVA &#xff5c;日常开发中常见问题归纳讲解 前言一、语法错误相关问题1.1 分号缺失或多余1.2 括号不匹配1.3 变量未定义或重复定义 二、数据类型相关问题2.1 数据类型不匹配2.2 整数溢出和浮点数精度问题 三、面向对象编程相关问题3.1 空指针异常&#xff08;NullPointerExc…

Git常用命令参考手册

Git常用命令参考手册 整理了一篇git常用的命令参考手册&#xff0c;命令顺序按照一个项目从头到尾的常用命令顺序做了排序&#xff0c;后续会继续完善内容示例并补全其他命令使用说明&#xff0c;希望对不熟悉的小伙伴有所帮助。 git config # 配置列表 git config --list #…

翰高4.5.7安装测试手册centos

翰高4.5.7centos版本安装 1 环境准备 产品包&#xff1a;hgdb4.5.7-see-centos7-x86-64-20210804.rpm 环境&#xff1a;10.1.5.172 root/sh88861158 操作系统安装完成后&#xff0c;执行常规操作&#xff1a;修改hosts、关闭防火墙、关闭senliunx 2 安装步骤 2.1 安装前准…

港科夜闻 |香港科大推出 InvestLM生成式人工智能平台,支持金融中小企应用AI技术潜力...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大推出 InvestLM生成式人工智能平台&#xff0c;支持金融中小企应用AI技术潜力。香港科大商学院继去年研究团队成功开发本港首个专为金融界而设、应用于生成式人工智能(生成式AI)的开源大语言模型InvestLM后&#…

【计算机网络】实验6:IPV4地址的构造超网及IP数据报

实验 6&#xff1a;IPV4地址的构造超网及IP数据报 一、 实验目的 加深对IPV4地址的构造超网&#xff08;无分类编制&#xff09;的了解。 加深对IP数据包的发送和转发流程的了解。 二、 实验环境 • Cisco Packet Tracer 模拟器 三、 实验内容 1、了解IPV4地址的构造超网…

FreeRtos开发之计数信号量

前面介绍过了计数信号量的定义取值只有0与1两种状态的信号量称之为二值信号量 取值大于1的信号量称之为计数信号量 计数信号量的取值也可以为1&#xff0c;但通常大于1&#xff0c;如果取值为1&#xff0c;相当于只有0与1两种状态&#xff0c;用二值信号量即可。 计数信号量应用…

Profinet转EtherNet/IP网关是如何解决西门子S7-1500PLC与AB PLC的通讯问题的

一、 案例背景 在一个工业现场&#xff0c;一端是AB的PLC&#xff0c;IP地址192.168.1.20;另一端西门子是S7-1500系列&#xff0c;IP地址192.168.2.248。AB的PLC内有 B3、N7、F8 三个寄存器文件涉及到通讯&#xff0c;分别对应西门子PLC的M、DB1、DB2三个存储区域。通过捷米特…

【C语言】扫雷游戏(一)

我们先设计一个简单的9*9棋盘并有10个雷的扫雷游戏。 1&#xff0c;可以用数组存放&#xff0c;如果有雷就用1表示&#xff0c;没雷就用0表示。 2&#xff0c;排查(2,5)这个坐标时&#xff0c;我们访问周围的⼀圈8个位置黄色统计周围雷的个数是1。排查(8,6)这个坐标时&#xf…

Unity开发FPS游戏之完结篇

这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏&#xff0c;感兴趣的朋友可以回顾一下。这个系列的文章如下&#xff1a; Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…

浅析RPC—基础知识

该文章会简单介绍一下 RPC 相关的基础概念。 什么是RPC&#xff1f; RPC&#xff08;Remote Procedure Call&#xff09; 即远程过程调用&#xff0c;通过名字我们就能看出 RPC 关注的是远程调用而非本地调用。 为什么要 RPC &#xff1f; 因为&#xff0c;两个不同的服务器…

mysql数据库varchar截断问题

用了这么多年mysql数据库&#xff0c;才发现varchar是可以截断的&#xff0c;而且是在我们线上数据库。个人觉得dba的这个设置是非常有问题的&#xff0c;用户往数据库里存东西&#xff0c;就是为了以后用的&#xff0c;截断了存放&#xff0c;数据不完整&#xff0c;就用不了了…

EwoMail邮箱服务器软件安装教程

EwoMail是基于Linux的开源邮件服务器软件,集成了众多优秀稳定的组件,是一个快速部署、简单高效、多语言、安全稳定的邮件解决方案,帮助你提升运维效率,降低 IT 成本,兼容主流的邮件客户端,同时支持电脑和手机邮件客户端。 一、系统版本 二、关闭selinux vi /etc/sysconf…

【机器学习】机器学习的基本分类-监督学习-支持向量机(Support Vector Machine, SVM)

支持向量机是一种强大的监督学习算法&#xff0c;主要用于分类问题&#xff0c;但也可以用于回归和异常检测。SVM 的核心思想是通过最大化分类边界的方式找到数据的最佳分离超平面。 1. 核心思想 目标 给定训练数据 &#xff0c;其中 是特征向量&#xff0c; 是标签&#xf…

Linux命令进阶·如何切换root以及回退、sudo命令、用户/用户组管理,以及解决创建用户不显示问题和Ubuntu不显示用户名只显示“$“符号问题

目录 1. root用户&#xff08;超级管理员&#xff09; 1.1 用于账户切换的系统命令——su 1.2 退回上一个用户命令——exit 1.3 普通命令临时授权root身份执行——sudo 1.3.1 为普通用户配置sudo认证 2. 用户/用户组管理 2.1 用户组管理 2.2 用户管理 2.2.1 …

Zero to JupyterHub with Kubernetes中篇 - Kubernetes 常规使用记录

前言&#xff1a;纯个人记录使用。 搭建 Zero to JupyterHub with Kubernetes 上篇 - Kubernetes 离线二进制部署。搭建 Zero to JupyterHub with Kubernetes 中篇 - Kubernetes 常规使用记录。搭建 Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s。 参考&…

《Python基础》之Python中可以转换成json数据类型的数据

目录 一、JSON简介 JSON有两种基本结构 1、对象&#xff08;Object&#xff09; 2、数组&#xff08;Array&#xff09; 二、将数据装换成json数据类型方法 三、在Python中&#xff0c;以下数据类型可以直接转换为JSON数据类型 1、字典&#xff08;Dictionary&#xff09…