深入理解进程的退出、等待与替换(Linux系统)

个人主页:敲上瘾-CSDN博客

个人专栏:Linux学习、游戏、数据结构、c语言基础、c++学习、算法

目录

一、进程退出

1.退出场景

2.常见退出方法

3.退出码与退出信号

4._exit函数与exit函数

二、进程等待

1.什么是进程等待(是什么?)

2.为什么要有进程等待(为什么?)

3.如何进行进程等待(怎么办?)

3.1.wait

3.2.waitpid

3.3.获取status

3.4.阻塞与非阻塞等待

三、进程替换

1.进程替换原理

2.进程替换函数


一、进程退出

1.退出场景

进程退出一共就三种情况:

  • 进程正常退出,执行结果正确
  • 进程正常退出,执行结果错误
  • 进程异常退出

2.常见退出方法

  • main函数中return退出
  • 使用_exit函数退出
  • 使用exit函数退出

_exit和exit在下文详解。

3.退出码与退出信号

  • 退出码:标识程序的退出状态
  • 退出信号:当程序异常退出后,退出信号标记了进程异常退出的原因,如果是正常退出则退出信号为0。

在对于退出信号可以使用 kill -l 查询,如下:

4._exit函数与exit函数

        _exit是一个系统提供的接口,它的参数是一个int类型,需要传一个退出信号返回。而exit是C语言提供的接口,它同样是让程序退出,需要传一个退出信号返回。

        而_exit与exit一个很大的区别就是_exit不会刷新缓冲区,而exit会刷新缓冲区,其中exit底层还是使用了_exit实现。

可以做一个简单的小测试:

注意:(1)这里程序是从exit和_exit退出的,而不是从return 0退出。(2)这里我有意在printf输出字符串后没有加\n,因为\n会让缓冲区刷新,会干扰测试。

二、进程等待

1.什么是进程等待(是什么?)

进程等待指的是父进程等待子进程结束。

        在子进程结束后它的pcb不会立马释放,而是进入僵尸状态,让父进程回收。当然如果父进程永远不来回收,那么子进程pcb就永远得不到释放,从而内存泄漏

而父进程在等待子进程退出这个过程就叫作进程等待。

2.为什么要有进程等待(为什么?)

  • 父进程创建子进程就是要子进程完成任务,所以父进程需要知道任务的完成情况,从而决定下一步要做什么。
  • ⼦进程退出,⽗进程如果不管不顾,就可能造成 僵⼫进程 的问题,进⽽造成内存泄漏。
  • ⽗进程通过进程等待的⽅式,回收⼦进程资源,获取⼦进程退出信息(任务完成情况)。

3.如何进行进程等待(怎么办?)

3.1.wait

        wait是一个用来进程等待的函数,使用它需要包含的头文件为 sys/types.hsys/wait.h。函数声明如下:

pid_t wait(int *status);
  • 返回值:成功返回被等待进程pid,失败返回-1。
  • 参数:输出型参数,获取⼦进程退出状态,不关⼼则可以设置成为NULL。

3.2.waitpid

        waitpid同样是一个用来进程等待的函数,它的功能要更多,使用它需要包含的头文件为 sys/types.h 和 sys/wait.h。函数声明如下:

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

返回值:

  • 当正常返回的时候waitpid返回收集到的⼦进程的进程ID;
  • 如果第三个参数设置了选项WNOHANG,那么调⽤中waitpid发现没有已退出的⼦进程可收集,否则返回0。
  • 如果调⽤中出错,则返回-1,这时errno会被设置成相应的值以指⽰错误所在;

参数:

  • 1.pid:(1)pid=-1,等待任⼀个⼦进程。与wait等效(2)pid>0,等待其进程ID为pid的⼦进程。
  • 2.status:输出型参数,获取⼦进程退出状态,不关⼼则可以设置成为NULL。下面3.3.再细讲。
  • 3.options:默认为0,表⽰如果子进程没有结束需要等待。如果设置为WNOHANG,子进程没有结束则不需要等待,接着往下执行。
     

3.3.获取status

status可以得到进程的退出码和退出信号。

        它是如何同时储存退出码和退出信号呢?其实用了一个位图的思想。status是一个int类型一共占4*8个比特位。而这里用了它的低16位,如下:

所以退出码我们可以使用(status>>8)&0xFF获取,退出信号通过status&0x7F获取。当然系统给我们提供了WIFEXITED和WEXITSTATUS两个宏来做进程退出状态检查。功能如下:

  • WIFEXITED(status):若为正常终⽌⼦进程返回的状态,则为真(查看进程是否是正常退出)。
  • WEXITSTATUS(status):若WIFEXITED⾮零,提取⼦进程退出码(查看进程的退出码)。

3.4.阻塞与非阻塞等待

        阻塞等待:使用wait或使用waitpid第三个参数传0的话,父进程在等待子进程过程中,如果子进程没有结束,那么父进程就会一直等。直到子进程退出。        

        非阻塞等待:父进程是很忙的,当子进程没有退出的时候也不能在那里干等着。所以正如刚才所讲,waitpid第三个参数中传入WNOHANG就能实现子进程还没退出就不等,继续做自己的其他工作,这就是非阻塞等待。当然刚才没有等到子进程结束,还得找个时间再等,要不然到时候子进程pcd就不能被回收。所以如果使用WNOHANG就需要重复的waitpid,这就是非阻塞轮询

三、进程替换

1.进程替换原理

如下是一个程序替换的程序(execl函数使用在下文会讲解):

#include<stdio.h>
#include<unistd.h>
int main()
{execl("/usr/bin/ls","/usr/bin/ls","-la",NULL);//程序替换printf("hello linux\n");return 0;}

        进程替换就是在一个进程执行中把该进程后续的内容替换成其他进程。要知道指令的本质就是一个可执行文件,它是用c语言写的。以上代码就相当于把ls这个程序的代码把后面的原代码覆盖掉,所以其中pcd,虚拟地址空间,页表并没有改变,而是物理内存改变了

注意:(1)进程替换并不会有新的进程生成。(2)进程替换可以替换为任何进程,无论是什么语言,打个比方就是说,x写的程序,在执行过程中可以替换成y写的程序(x,y表示任意语言)。

2.进程替换函数

如下是一个exec函数族,即程序替换函数族:

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

替换一个程序起码要知道这个程序的路径吧?需要知道它的名字吧?还需要知道命令行参数吧?

  • 第一个参数:需要替换的程序的路径。
  • 第二个参数:需要替换的程序的名字。
  • 第三个参数:给改程序传入命令行参数。
  • 第四个参数:如果有这个参数,需要传入自己组装的环境变量。如果没有改参数不用传,就用当前的环境变量。

上面函数的命名特点如下:

  • l(list):表⽰参数采⽤列表传入。
  • v(vector):参数⽤数组。
  • p(path):有p⾃动搜索环境变量PATH。
  • e(env):表⽰⾃⼰维护环境变量。

这些exec族的返回规则是一样的,如果执行成功没有返回值,如果调用失败返回-1。

如下代码是对该篇文章知识的应用:

#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>char* const g_argev1[]={(char* const)"/usr/bin/ls",(char* const)"-a",(char* const)"-l",NULL};char* const g_argev2[]={(char* const)"ls",(char* const)"-a",(char* const)"-l",NULL};char* const env[]=    //这里的环境变量是随便设的没有实际的意义,只是为了说明问题{(char* const)"HPP=128",(char* const)"GHH=29",(char* const)"p=..",NULL};int main()
{pid_t id=fork();if(id==0){execl("/usr/bin/ls","ls","-l","-a",NULL);//execv(g_argev1[0],g_argev1);//execlp("ls","-ln","-a",NULL);//execvp(g_argev2[0],g_argev2);//execle("./code","ls","-l","-a",NULL,env);//execve(g_argev1[0],g_argev2,env);exit(1); // 如果所有exec都失败,则执行到这里}int status;pid_t p=waitpid(id,&status,0);if(p>0){if(WIFEXITED(status))printf("exit code:%d, exit signal:%d\n",WEXITSTATUS(status),status&0x7F);// 注意:status&0x7F 用于获取终止信号,但通常我们只关心 WEXITSTATUS(status)elseprintf("程序执行异常\n");}elseprintf("waitpid fail:%s",strerror(errno));return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【初阶数据结构与算法】二叉树链式结构刷题训练(Leetcode二叉树遍历、单值二叉树、相同的树、另一棵树的子树、对称二叉树)

文章目录 一、二叉树的遍历二、单值二叉树三、相同的树四、另一颗树的子树五、对称二叉树 一、二叉树的遍历 在链式二叉树的定义与实现中我们已经详细讲解了二叉树常见的三种遍历方式&#xff0c;以及层序遍历&#xff0c;这里给出链接&#xff1a;【初阶数据结构与算法】二叉树…

深入浅出 Go 语言 sync包中的互斥锁、条件变量

深入浅出 Go 语言 sync包中的互斥锁、条件变量 引言 在并发编程中&#xff0c;多个 Goroutine 同时访问共享资源可能会导致数据竞争&#xff08;Race Condition&#xff09;&#xff0c;进而引发程序的不一致性或崩溃。为了确保并发程序的正确性和稳定性&#xff0c;Go 语言提…

制造业数据集成案例分享:3小时内实现MySQL到MySQL数据对接

ZZ刷新生产用料清单四化库存-制造一处-3小时&#xff1a;MySQL到MySQL数据集成案例分享 在现代制造业中&#xff0c;实时、准确的数据流动是确保生产效率和资源优化的关键。本文将分享一个实际运行的系统对接集成案例——“ZZ刷新生产用料清单四化库存-制造一处-3小时”&#…

OpenCV 图像基本操作

OpenCV快速通关 第一章&#xff1a;OpenCV 图像基本操作 第二章&#xff1a;OpenCV 图像基本操作 OpenCV 图像基本操作 OpenCV快速通关第二章&#xff1a;OpenCV 图像基本操作一、相关结构体与函数介绍&#xff08;一&#xff09;cv::Mat 结构体&#xff08;二&#xff09;cv:…

雨晨 2610(2)0.2510 Windows 11 24H2 Iot 企业版 LTSC 2024 极简 2in1

文件: 雨晨 2610(2)0.2510 Windows 11 24H2 Iot 企业版 LTSC 2024 极简 2in1 install.esd 索引: 1 名称: Windows 11 IoT 企业版 LTSC 极简 26100.2510 描述: Windows 11 IoT 企业版 LTSC 极简 26100.2510 By YCDISM RTM 2025 24-12-07 大小: 8,176,452,990 个字节 索引: 2 …

PHP保存base64编码图片,图片有一部分是灰色块儿,原因和解决办法

文章目录 场景原因解决方案完整的代码前端代码php代码 场景 我有个需求&#xff0c;移动端h5上传多张的图片。用input file可以上传多张&#xff0c;但是现在照片体积越来越大&#xff0c;同时上传多张会因为体积过大&#xff0c;导致上传失败。如果是小程序会好很多&#xff…

【CSP CCF记录】202212-2第28次认证 训练计划

题目 样例1输入 10 5 0 0 0 0 0 1 2 3 2 10 样例1输出 1 1 1 1 1 10 9 8 9 1 样例1解释 五项科目间没有依赖关系&#xff0c;都可以从第 1 天就开始训练。 10天时间恰好可以完成所有科目的训练。其中科目 1 耗时仅 1天&#xff0c;所以最晚可以拖延到第 10 天再开始训练&…

gitee

Git 是一个开源的 [ 分布式 ][ 版本控制系统 ] &#xff0c;用于敏捷高效地 处理任何或小或大的项目 Git 非常容易学习&#xff0c;低植入&#xff0c;高性能。因为拥有轻量的本地分支&#xff0c;易用的暂存区&#xff0c;和多工作流的特点&#xff0c;它超越了类似Subversio…

Spring——SpringBean初始接口

摘要 本文详细介绍了Spring框架中SpringBean的初始化接口和注解&#xff0c;包括BeanPostProcessor接口、InitializingBean接口和PostConstruct注解。文章解释了这些接口和注解的原理、作用、适用场景&#xff0c;并提供了示例代码。最后&#xff0c;对比了不同SpringBean初始…

「嵌入式系统设计与实现」书评:学习一个STM32的案例

本文最早发表于电子发烧友论坛&#xff1a;【新提醒】【「嵌入式系统设计与实现」阅读体验】 学习一个STM32的案例 - 发烧友官方/活动 - 电子技术论坛 - 广受欢迎的专业电子论坛!https://bbs.elecfans.com/jishu_2467617_1_1.html 感谢电子发烧友论坛和电子工业出版社的赠书。 …

操作系统——大容量存储结构

笔记内容及图片整理自XJTUSE “操作系统” 课程ppt&#xff0c;仅供学习交流使用&#xff0c;谢谢。 大容量存储结构概述 磁盘 磁盘为现代计算机系统提供大量外存。每个盘片为平的圆状&#xff08;类似CD&#xff09;&#xff0c;普通盘片直径为4.5~9.0厘米。盘片的两面都涂着…

Redis从入门到进阶(总结)

以下内容均以CentOS7为背景。 一、Redis安装及启动 mysql&#xff08;读&#xff1a;2000/s&#xff1b;写&#xff1a;600/s&#xff09; redis&#xff08;读&#xff1a;10w/s&#xff1b;写&#xff1a;8w/s&#xff09;通过官方给出的数据单机并发可以达到10w/s&#xf…

Java进阶(注解,设计模式,对象克隆)

Java进阶(注解&#xff0c;设计模式&#xff0c;对象克隆) 一. 注解 1.1 什么是注解 java中注解(Annotation)&#xff0c;又称java标注&#xff0c;是一种特殊的注释 可以添加在包&#xff0c;类&#xff0c;成员变量&#xff0c;方法&#xff0c;参数等内容上 注解会随同…

使用 Gin 框架构建 RESTful 博客 API

使用 Gin 框架构建 RESTful 博客 API 引言 在现代 Web 开发中&#xff0c;RESTful API 是一种非常流行的设计风格&#xff0c;它通过 HTTP 协议与客户端进行通信&#xff0c;提供了灵活且易于扩展的接口。Go 语言以其高效的并发处理能力和简洁的语法&#xff0c;成为了构建高…

Leecode刷题C语言之骑士在棋盘上的概率

执行结果:通过 执行用时和内存消耗如下&#xff1a; 代码如下&#xff1a; static int dirs[8][2] {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}};double knightProbability(int n, int k, int row, int column){double dp[200][30][30];mem…

21. C++STL 7(8000字详解list及其迭代器的模拟实现)

⭐本篇重点&#xff1a;STL中的list及其迭代器的模拟实现和测试 ⭐本篇代码&#xff1a;c学习 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) 目录 一. list的节点 二. list的迭代器 2.1 迭代器框架 2.2 迭代器实现 三. list的实现 3.1 list的构造函数 3.…

Docker打包SpringBoot项目

一、项目打成jar包 在进行docker打包之前&#xff0c;先确定一下&#xff0c;项目能够正常的打成JAR包&#xff0c;并且启动之后能够正常的访问。这一步看似是可有可无&#xff0c;但是能避免后期的一些无厘头问题。 二、Dockerfile 项目打包成功之后&#xff0c;需要编写Doc…

零基础学鸿蒙开发--第九篇--网络请求

12. ⽹络请求 鸿蒙系统提供了 http 模块 ⽤于发送 http 请求&#xff0c;另外&#xff0c; OpenHarmony社区基于该模块将前端开发中常⽤的⽹络请 求库 axios 移植到了鸿蒙系统&#xff0c;因此我们也可以在鸿蒙系统中使⽤ axios 发送 http 请求&#xff0c;下⾯重点为⼤家介绍…

133.WEB渗透测试-信息收集-小程序、app(4)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;132.WEB渗透测试-信息收集-小程序、app&#xff08;3&#xff09; 输入命令&#xff1a;…

Pointnet++改进71:添加LFE模块|高效长距离注意力网络

简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入LFE模块,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三 1.理…