第三部分:5---进程等待、进程终止

news2024/9/22 10:05:45

目录

进程的两种终止方式:

正常终止——进程退出码:

查看最近一次进程退出的退出码:

自定义退出码对应的文本信息:

退出码和C语言的错误码的关系:

异常终止——操作系统发送信号:

————————————————

exit 和 _exit终止进程的区别:

————————————————

什么是进程等待?

为什么要等待进程?

wait实现进程等待:

waitpid实现进程等待:

对status的解析:

为什么不写一个status全局变量,直接接收子进程的退出码?

对options的解析 / 进程的非阻塞等待:


进程的两种终止方式:

  • 正常终止:当进程完成其所有任务后,自行结束,并返回一个退出码。这个退出码通常通过 main 函数的返回值或 exit() 函数指定。正常终止的进程会将退出码传递给操作系统和父进程,用于告诉其结束原因。

  • 异常终止:当进程在运行过程中因某种原因未能正常完成而被迫终止。这通常是由于进程收到来自操作系统的信号,例如 SIGKILL 或 SIGSEGV。信号可能由用户(用户可以手动向进程发送信号使其终止,例如:“ kill -9 pid ”)、操作系统或其他进程触发,表示进程需要立即停止。异常终止的进程可能不会有机会返回一个正常的退出码,信号本身就代表了进程的终止原因。

  • 正常终止和异常终止的区别在于,正常终止是进程在预期的条件下完成工作并返回退出码,而异常终止则是由于外部或内部的意外情况导致的强制结束。

正常终止——进程退出码:

  • main 函数的返回值(退出码)会传递给父进程,表示子进程的退出状态。这一返回值可以告诉父进程子进程是如何结束的,并指示其执行结果是否正确。

  • 返回值为 0 表示子进程正常结束,这通常表示程序执行成功,没有遇到任何错误。

  • 返回值为非 0 表示子进程异常结束。不同的非零值代表不同的错误原因或异常情况。程序可以通过返回特定的数字值来表明特定的错误类型,从而为父进程提供详细的错误信息。

  • 纯数字的返回值虽然简洁,但在表达错误原因时可能不够直观。Unix/Linux 系统中的 strerror 函数可以将错误代码转换为对应的错误描述字符串。这种机制使得程序能够有效地报告错误原因,并帮助开发者或父进程做出相应的处理,如记录日志、重试操作或采取其他补救措施。

for(int i=0;i<n;i++)
{
	printf(" %d : %s\n",i,strerror(i)); //通过strerror(num)打印退出码对应的出错原因
}

查看最近一次进程退出的退出码:

echo $? //打印最近一个进程退出时的退出码,这个退出码存放在?中

自定义退出码对应的文本信息:

const char* err_string[]={"SUCCESS" , "OPER ERROR"};//定义了两个退出码(1和2)对应的信息

退出码和C语言的错误码的关系:

  • 在 C语言 中,有一个全局变量 errno,它用于获取最近一次函数调用出错时的错误码。errno 通常在库函数或系统调用出错时被设置,以提供关于错误原因的详细信息。

  • errno 返回的错误码 主要反映库函数或系统调用在执行过程中出现的问题。例如,如果文件打开失败,errno 可能会被设置为 ENOENT,表示文件不存在。通过检查 errno,程序可以了解调用失败的具体原因,并采取相应的处理措施。

  • 退出码(exit status) 是进程退出时返回给操作系统的一个状态值,用于指示进程的退出情况。main 函数的返回值或通过 exit() 函数指定的值将成为退出码。退出码为 0 通常表示进程成功结束,非零值则表示进程以某种错误或异常状态结束。

  • 虽然 errno 和退出码的作用不同,但它们的共同目的是在函数调用或进程执行完成后,提供关于出错原因的详细信息。errno 主要用于函数级别的错误处理,而退出码则用于进程级别的状态报告。

//将程序的退出码与系统的错误码关联起来,在函数调用失败后,可以直接打印得到失败的原因。

int main()
{
	int ret=0; 
	FILE* file=fopen("./111.txt","w"); //打开一个不存在的文件,file会被设置为nullptr
	if(file==nullptr)
	{
		ret=errno; //将返回值设置为errno的出错码
	}
	return ret; //返回出错吗,可以直接得知出错原因
}

异常终止——操作系统发送信号:

  • 如果进程异常终止,这意味着进程的代码未能正常执行完毕,因此退出码对于这种情况没有意义。退出码只在进程顺利完成其任务并正常退出时才有意义,能够反映执行结果的状态。

  • 当进程出现异常时,操作系统会主动终止该进程,通常是通过向进程发送信号来实现。常见的信号包括 SIGKILL(强制终止)和 SIGSEGV(段错误)。这些信号会立即中断进程的执行,迫使其停止运行。

  • 进程异常的本质在于它收到了操作系统发来的信号,并因此自行终止。信号的发送通常意味着进程执行过程中发生了严重错误或不允许的操作,操作系统通过发送信号来防止问题进一步扩展。

  • 因此,判断一个进程是否异常终止,只需要查看该进程是否收到了操作系统发出的信号即可。信号的接收与处理是判断进程是否因异常情况被终止的关键依据。

————————————————

exit 和 _exit终止进程的区别:

  • exit 函数属于 C 标准库,用于终止进程并返回到操作系统。exit 会执行一系列的清理操作,包括自动刷新标准 I/O 流的缓冲区,以确保所有缓冲的数据被写入到目标文件或设备。

  • _exit 是一个系统调用,直接终止进程,不进行任何额外的清理操作。 _exit 直接从内核返回,跳过了标准库的缓冲区处理机制。因此,它不会刷新缓冲区,任何尚未写入的数据都会被丢弃。

  • exit 是对 _exit 的封装,在 _exit 的基础上增加了额外的功能,包括刷新所有的缓冲区、关闭文件描述符等。这些操作确保了在进程退出之前,所有相关资源都被正确处理。

  • 为什么 _exit 不会刷新缓冲区而 exit 会?原因在于:缓冲区的管理是在 C 标准库中完成而不是操作系统内部。 _exit 是直接与操作系统交互的系统调用,它跳过了标准库的清理步骤,因此不能刷新缓冲区。而 exit 函数则会调用标准库中的清理函数来处理缓冲区数据,因为缓冲区管理是由 C 标准库负责的,而不是操作系统直接处理的。

————————————————

什么是进程等待?

  • 进程等待就是通过 wait / waitpid 的方式,让父进程等待子进程终止后,对子进程回收资源的过程。

为什么要等待进程?

  • 在子进程结束后,父进程需要等待子进程的终止,以释放变为僵尸进程的子进程,从而防止系统资源的泄漏。

  • 父进程等待子进程结束的原因之一,是为了获取子进程的退出码。这个退出码提供了子进程执行任务后的状态和信息,使父进程能够了解子进程是否成功完成了其任务,或者发生了何种错误。基于这些信息,父进程可以采取相应的措施,比如记录日志、重试操作、或处理错误等。

wait实现进程等待:

pid_t wait(int *status);
//int *status:指向一个整数变量的指针,用于存储子进程的退出状态。如果你不关心退出状态,可以传递 NULL。
//成功时,wait返回终止的子进程的进程 ID。
//如果调用时没有子进程,则返回 -1,并设置 errno 以指示错误类型。

int status;
pid_t child_pid = wait(&status);  // 等待子进程终止
  • 等待任意一个子进程结束后返回。

  • 父子进程,哪一个先被调用,操作系统直到我们不知道。但是父子进程哪一个先结束,必定是父进程要等待子进程结束,释放其僵尸状态的PCB。

waitpid实现进程等待:

pid_t waitpid(pid_t pid, int* status, int options);
//返回值如果大于0,表示等待成功可以下一步操作了。
//返回值如果小于0,表示子进程等待失败。
//返回值如果等于0,表示子进程还在运行没有退出。
//等待指定pid的子进程结束后执行。pid被设置为-1后,作用变为等待任意一个子进程结束。
//options被设置为0,表示-阻塞等待。

对status的解析:

  • status 是一个输出类型参数,通常用于 wait() 或 waitpid() 系统调用,用来接收子进程的退出状态。

  • status 是一个 int 类型的变量,包含了 32 个比特位。这些比特位用于存储子进程的退出码、退出信号以及其他与进程终止相关的信息。

 

  • 当子进程终止时,它会将自己的退出码和退出信号信息写入到自己的进程控制块(PCB)中。父进程通过调用 wait() 或 waitpid() 系统调用,能够获取子进程的退出信息。这两个系统调用会将子进程的退出码和退出信号提取出来,并将这些信息写入到 status 变量中,从而让父进程可以读取和处理。

WIFEXITED(status) //得到进程退出码

为什么不写一个status全局变量,直接接收子进程的退出码?

  • 根据之前对虚拟地址和物理地址的分析可知,在父子进程之间,即使全局变量在同一份代码中定义,它们在内存中的物理地址也不会相同。虽然父子进程共享相同的代码和相同的虚拟地址空间布局,但它们的全局变量在实际物理内存中会被映射到不同的物理地址上。

  • 因此,父进程无法直接访问子进程的数据。由于父子进程的全局变量映射到不同的物理地址上,父进程无法通过简单的变量访问来获取子进程的数据。

  • 要在父子进程之间传递数据,需要通过操作系统提供的系统调用来实现。例如,父进程可以通过 wait()、waitpid() 等系统调用获取子进程的退出状态,也可以通过管道(pipe)、共享内存(shared memory)、消息队列(message queue)等进程间通信机制来传递更复杂的数据。

对options的解析 / 进程的非阻塞等待:

  • 当将传递给 waitpid 的 options 参数设为 0 时,意味着 waitpid 采用的是“阻塞等待”模式。在这种模式下,父进程会一直阻塞,直到有一个子进程终止为止。在阻塞期间,父进程无法执行其他任务,必须等待子进程的状态变化。

  • 如果传递给 options 的值为宏 WNOHANG,则 waitpid 将采用“非阻塞等待”模式。在这种模式下,如果没有子进程立即终止,waitpid 会立即返回,并不会阻塞父进程。父进程可以继续执行其他操作,并在适当的时机再次调用 waitpid 来检查子进程的状态。

  • 常见的非阻塞等待方案就是“非阻塞轮询”,即父进程通过定期调用 waitpid 并结合 WNOHANG 宏来检查子进程的状态。轮询指的是父进程反复检查子进程状态的行为,而非阻塞则确保了在子进程未终止时,父进程不会被阻塞,可以继续执行其他任务。

  • 相比于阻塞等待模式下父进程什么都不能做,非阻塞等待使父进程可以在等待子进程终止的同时处理其他任务。这种方式有效提高了父进程的效率,特别是在需要处理多个子进程或需要持续执行其他任务的情况下。  

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

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

相关文章

java基础-IO(6)转换流InputStreamReader、OutputStreamWriter

引入&#xff1a; 从第一节可知&#xff0c;流分为两类&#xff1a;字节流和字符流&#xff0c;转换流就是在两者之间进行转换。 字节流转换为字符流&#xff1b; 字符流转换为字节流。 字符集 字符集&#xff1a;定义了可用字符及其对应的数字编码的集合。常见的字符集有UT…

1.Python解释器和Pycharm安装设定

Python是一种动态的&#xff0c;解释型语言&#xff0c;需要安装Python解释器。安装Python后&#xff0c;可以使用其自带的编码工具来编写代码。也可以使用第三方的工具&#xff0c;这里使用Pycharm,它有很多优点&#xff0c;可以提高代码编写和编码调试效率。 一、Python解释…

nacos 安装 centos7 docker

一、拉取镜像 docker pull nacos/nacos-server二、创建容器 ①一般 docker run -d --name nacos-server -p 8848:8848 -e MODEstandalone nacos/nacos-server②通过配置文件配置相关环境变量 1上传文件 2创建 docker run -d \ --name nacos \ --env-file ./nacos/custom.env …

【C++ Primer Plus习题】14.3

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "queuetp.h&quo…

151-钓鱼篇邮件钓鱼SPF绕过自建邮件系统SwaksGophish

前置内容: 1、什么是SPF: 发件人策略框架(Sender Policy Framework)电子邮件认证机制中文译为发送方策略框架&#xff0c;主要作用是防止伪造邮件地址。可以把 SPF 记录看成是一个合法 IP 地址的白名单&#xff0c;当进来的邮件来自一个白名单中指定的 IP 地址&#xff0c;SP…

Java中的常用类及包装类

目录 Java中的常用类及包装类 Math类 Math类常用方法 BigInteger类 创建BigInteger类对象 常用方法 BigDecimal类 创建BigDecimal类对象 常用方法 Date日期类 创建Date类对象 常用方法 Calendar类 获取Calendar类实例 常用方法 SimpleDateFormat类 创建SimpleDateFormat类对象 …

燃气涡轮发动机性能仿真程序GSP12.0.4.2使用经验(二):使用GSP建立PG9351FA燃气轮机性能仿真模型

目录 一、PG9351FA燃气轮机简介及热力循环参数二、基于GSP的性能仿真模型设置环境参数设置进气道参数设置压气机参数设置燃烧室参数设置透平&#xff08;涡轮&#xff09;参数设置转子负载参数燃油流量外部控制 三、仿真结果四、其它 一、PG9351FA燃气轮机简介及热力循环参数 …

数据结构10

文章目录 两两交换链表中的节点括号生成I2009 408应用题42题 两两交换链表中的节点 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullp…

Mysql基础练习题 1407.排名靠前的旅行者(力扣)

编写解决方案&#xff0c;报告每个用户的旅行距离。 # 返回的结果表单&#xff0c;以 travelled_distance 降序排列 &#xff0c;如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列 。 题目链接&#xff1a; https://leetcode.cn/problems/top-travellers/d…

页面水印的实现以及防删除方案

水印相关 引言绘制一个水印输出背景图封装一点点细节图片加水印防止水印删除问题解决方案 引言 在企业里为了防止信息泄露和保护知识产权&#xff0c;通常会在页面和图片上添加水印 前端页面水印的添加一般有这几种方式&#xff1a;dom 元素循环、canvas 输出背景图、svg 实现…

vite项目配置本地开发使用https访问

在Vite项目中启用HTTPS以安全地使用navigator.mediaDevices.getUserMedia() 引言 在现代Web开发中&#xff0c;保护用户隐私和数据安全是至关重要的。特别是在涉及到媒体捕获功能&#xff0c;如使用用户的摄像头或麦克风时&#xff0c;Web应用需要遵循严格的安全准则。naviga…

《生成式人工智能行业自律倡议》发布,BAT、华为小米 OPPO 荣耀、北大清华等参编

8 月 29 日,在成都举办的 2024 年中国网络文明大会上,《生成式人工智能行业自律倡议》正式发布。 《生成式人工智能行业自律倡议》从保障数据和算法模型安全合规、促进内容生态建设、追求技术创新与质量提升、遵循价值观与伦理道德标准和促进交流合作与开放共建等方面发出行…

Marin说PCB之在CST软件中如何搭建两端子电容器--01

今天是教师节&#xff0c;小编首先祝愿所有的老师们节日快乐&#xff0c;当然还有我的那些国外的老师们&#xff0c;道友们懂得都懂啊&#xff0c;我就不说破了&#xff0c;都毕业很多年了&#xff0c;小编我还是很怀念大学的时光的&#xff0c;毕竟那个时候我也是有很多女粉丝…

CCOS2024盛大举办, 四川眼科医院专家亮相盛会并作精彩分享

名医荟萃&#xff0c;共襄盛举&#xff1b;学术争鸣&#xff0c;共话未来。9月4日-8日&#xff0c;中华医学会第二十八次眼科学术大会&#xff08;CCOS2024&#xff09;在武汉国际会议中心和武汉国际博览中心隆重举行&#xff01; 此次大会汇聚了来自全国各地的一万多名眼科同…

一、windows11交叉编译ffmpeg的android版本库

目录 1、工具准备 &#xff08;1&#xff09;MSYS2 &#xff08;2&#xff09;NDK&#xff08;也可直接用android studio安装的&#xff09; &#xff08;3&#xff09;ffmpeg源码 2、环境配置 3、创建编译脚本 4、编译 曾经看到一个博客说&#xff0c;不要用windows编译…

过程设计例题

答案&#xff1a;D 知识点&#xff1a; 体系结构设计 定义软件系统各主要部件之间的关系 数据设计 基于E-R图确定软件涉及的文件系统及数据库的表结构 接口设计&#xff08;人机界面设计&#xff09; 软件内部&#xff0c;软件和操作系统间以及软件和人之间如何通信 过程…

基于Springboot的鲜花销售网站的设计与实现

项目描述 这是一款基于Springboot的鲜花销售网站的系统 模块描述 鲜花销售系统 1、用户 登录 在线注册 浏览商品 鲜花搜索 订购商品 查询商品详情 水果分类查看 水果加购物车 下单结算 填写收货地址 2、管理员 登录 用户管理 商品管理 订单管理 账户管理 截图

代码随想录算法训练营第二十三天| 455. 分发饼干、376. 摆动序列、53. 最大子序和

今日内容 贪心理论基础Leetcode. 455 分发饼干Leetcode. 376 摆动序列Leetcode. 53 最大子序和 贪心理论基础 贪心算法的本质就是选择每一阶段的最优&#xff0c;达到全局上的最优。 贪心算法和之前学到的所有方法相比&#xff0c;它没有固定的使用套路&#xff0c;也没有固…

IEEE 802.11a OFDM系统的仿真

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第九章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; ​ ​ ​ clear all %%%%%%%参数设计部分%%%%%%%Nsp52;%系统子载波数&#xff08;不包括直流载波&#xff09; Nfft64;%FF…

【QT】自制一个简单的小闹钟,能够实现语音播报功能

做了一个自制的小闹钟&#xff0c;能够自己输入时间&#xff0c;以及对应的闹铃&#xff0c;时间到了自动播放设定的闹铃&#xff0c;可以随时取消重新设定&#xff0c;采用分文件编译 注意&#xff1a;需要在.pro文件中加入&#xff1a;QT core gui texttospeech 代码…