【Linux进程控制一】进程的终止和等待

news2025/5/10 12:08:20

【Linux进程控制一】进程的终止和等待

  • 一、进程终止
    • 1.main函数的return
    • 2.strerror函数
    • 3.库函数exit
    • 4.系统调用_exit和库函数exit的区别
    • 5.异常信号
    • 6.变量errno
  • 二、进程等待
    • 1.什么是进程等待?
    • 2.wait接口
    • 3.status
    • 4.waitpid接口

一、进程终止

1.main函数的return

写C/C++代码时总会在写了int main函数的结尾写return 0,但是程序肯定不止能return 0

1.main函数和非main函数执行到return语句时表示此函数执行完毕
2.程序正常执行完毕且结果正确时return返回0
3.程序正常执行完毕但结果不正确时return返回非0

非0值有很多,1、2、3、4等数字分别有什么含义呢?

2.strerror函数

在这里插入图片描述
作用:将错误码转换为错误字符串
在这里插入图片描述

在这里插入图片描述
0对应成功,且在134号错误之后都是未知错误
在这里插入图片描述
查看最近进程的退出码: 指令echo $?
测试echo $?指令:
在这里插入图片描述

在这里插入图片描述

所以return返回的就是错误码

3.库函数exit

在这里插入图片描述

exit的参数即为错误码,和main函数return的值一样

exit函数和return的区别:
1.return只有在main中使用时才能代表此进程退出
2.exit函数在程序任一地方使用都可以直接退出进程,并且返回错误码
测试一下:
在这里插入图片描述

在这里插入图片描述
使用echo $?打印出来的退出码是11

4.系统调用_exit和库函数exit的区别

man的2号手册可以看见_exit系统调用:
它和exit一样都是终止进程且_exit的参数也代表错误码
在这里插入图片描述
两个有什么区别?用两段代码来验证:

//第一次运行的代码:
	printf("打印成功!");
	exit(22);
//第二次运行的代码:
	printf("打印成功!");
	_exit(22);

在这里插入图片描述

第一次打印了文字,第二次没有打印

printf打印本质是行刷新,如果不使用\n换行数据就一直存储在缓冲区不会打印
当用库函数exit结束进程就能把缓冲区的数据打印出来(刷新缓冲区数据)
而系统调用_exit就不会刷新缓冲区数据

深入思考:
exit是C语言提供的库函数,而_exit是操作系统提供的系统调用,_exit无法刷新缓冲区就说明缓冲区不在操作系统内,也就是说缓冲区不由操作系统来维护,而是由C标准维护

5.异常信号

对于任意一个进程,都只有两种退出情况:
1.代码执行完毕,正常退出
2.进程发生了异常,被迫退出

命令行输入Ctrl+C传递信号杀掉进程是异常终止
比如说访问空指针,野指针,除零错误等等,这些都会导致进程直接终止

在这里插入图片描述
在这里插入图片描述
报出一个错误Floating point exception,说明可能存在 / 或者 % 的除数为 0 的情况,这就说明进程发生了异常
进程发生异常的本质,是收到了异常信号
通过指令kill -l来查看异常信号:
在这里插入图片描述
8号正是singal Floating point exception的缩写
在这里插入图片描述
该程序会陷入死循环,然后每隔一秒输出自己的pid
当进程执行起来后我们对其发送8信号
在这里插入图片描述
左侧窗口执行进程后,pid=559712,右侧窗口执行指令kill -8 559712,就向559712发送了8号信号,此时进程直接退出,并输出Floating point exception
明明是一个死循环,我们可以通过发送异常信号直接终止,而代码中明明没有除零错误,我们也可以通过信号对其强行加上异常

程序异常崩溃时,return的退出码是无意义的,因为退出码对应的return语句还没执行就已经崩溃了

6.变量errno

errno是C语言中的一个全局变量,它里面存储的是上一次函数调用的错误码,比如使用fopen函数打开文件时,如果打开失败不仅文件指针fp会被赋值为NULL,同时错误码errno也会被系统自动赋值
在这里插入图片描述
在这里插入图片描述
在当前目录下,不存在一个叫做111.c的文件,我们用fopen以r形式打开,那么fopen是打不开文件的,于是就会向errno进行写入
在这里插入图片描述
执行结果:输出了错误码2,strerror将错误码转换为错误字符串:即没有对应的文件或目录

二、进程等待

1.什么是进程等待?

进程等待用于回收子进程的资源,避免子进程的PCB一直占用资源,并且可以获取子进程的退出信息,得知子进程任务的执行情况,进程等待主要通过两个系统调用接口waitwaitpid来完成

2.wait接口

使用wait接口,需要包含头文件<sys/types.h><sys/wait.h>,其函数原型为:

pid_t wait(int* stat_loc);

wait的返回值是一个int类型
返回值大于0,返回等待到的子进程的pid
返回值小于0,等待失败
在这里插入图片描述
先通过fork创建了一个子进程
子进程进入if语句,进行五秒倒计时,然后退出,并且退出码为5
父进程则通过wait函数进行等待,传入指针&status,接收返回值pid,最后输出status和pid的值
在这里插入图片描述

  1. wait的返回值就是子进程的pid
  2. status一开始被初始化为0,wait之后,status = 1280,可知wait确实会修改传入的参数
  3. 子进程总共sleep了五秒,而父进程在等待的这五秒中,没有任何动作,就等着子进程结束,然后对它进行回收,这个过程父进程处于阻塞状态,称为阻塞等待

status为什么是1280?

3.status

status要当作一个位图来看:
在这里插入图片描述

  • 灰色部分:(status是一个int类型,占32比特)后16比特是无效的,不填入任何内容
  • 黄色部分:第8 - 15位,共8比特,表示wait到的子进程的退出码
  • 绿色部分:第7位,core dump标志位本章节不考虑该位置
  • 蓝色部分:第0 - 6位,共7比特,用户表示wait到的子进程的退出信号

因为return的退出码是5,二进制为0101,所以status后16位是0000 0101 0000 0000,转换为十进制正是wait修改后的status值1280,退出无异常所以退出信号为0

从status中提取出退出码和退出信号,就要对其进行位操作:

status直接与01111111进行按位与&,就能得到退出信号,01111111的十六进制表示为0X7F
int sig = status & 0x7F;

status右移8位后,与11111111进行按位与&,就能得到退出码,11111111的十六进制表示为0XFF
int code = (status >> 8) & 0xFF;

在这里插入图片描述
在这里插入图片描述
可以看到退出码为5,退出信号为0
Linux还给用户提供了两个宏函数,用于检测status:

WIFEXITED:检测进程是否正常退出,返回一个布尔值,如果进从正常退出,返回真
WEXITSTATUS:提取子进程的退出码,也就是第8 - 15位
使用:

if(WIFSIGNALED(status))
    printf("exit code = %d\n", WEXITSTATUS(status));
else
    printf("子进程退出异常...\n");

4.waitpid接口

进程等待的另外一个接口是waitpid接口,需要包含头文件<sys/types.h><sys/wait.h>,其函数原型为:

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

一个进程是可以有多个子进程的,但一个wait只能等待一个子进程,如果有多个子进程,那么wait函数只能等待第一个结束的子进程,而waitpid则是针对pid来对进程进行等待

waitpid的第一个参数是子进程的pid,第二个参数用于接收退出信息也就是刚刚的status,第三个参数用于控制等待的模式

通过代码验证wait和waitpid的区别:
在这里插入图片描述
我们通过fork创建了两个子进程,第一个子进程输出自己的pid后会sleep五秒,而第二个子进程输出pid后sleep一秒
父进程只wait一次,最后父进程输出wait的返回值,而返回值就是等待到的子进程的pid,这样就可以判断父进程wait到了哪一个子进程
在这里插入图片描述
child1的pid = 624488,child2的pid = 624489,而wait的返回值为624489,说明wait到了第二个进程。因为第二个进程先结束,所以被wait先接收了

现在我们把上述代码中的wait改为waitpid再次尝试:
在这里插入图片描述
通过waitpid的第一个参数,指定等待id1,也就是第一个子进程,第三个参数先设为0,后续讲解该参数的作用
在这里插入图片描述
返回值和child1匹配上了,可以说明虽然child1更晚结束,但是waitpid只会等待指定的进程,就算有其他子进程先结束了waitpid也不会去先回收

第三个参数用于控制进程等待的模式:

0:进行阻塞等待
WNOHANG:进行非阻塞等待

讲到wait时,简单提到了阻塞等待,也就是父进程在wait的时候,什么也不做,进入阻塞状态,直到wait成功

而非阻塞等待不同,进行非阻塞等待时,如果本次waitpid暂时没有等待到,那么父进程不会阻塞,waitpid直接返回0,表示本次等待没有等待到子进程。此时父进程就可以空出时间去完成别的任务,而不是什么也不做一直在等了

代码验证:
在这里插入图片描述
先通过fork创建了一个子进程,子进程sleep五秒。父进程陷入一个while死循环,每次循环开始,都以WNOHANG模式waitpid一次,由于该模式不会阻塞等待,只要当前子进程没有结束,那么waitpid直接返回0,去执行后面的if语句
如果当前返回值为0,说明当前子进程没有结束
如果当前返回值> 0,说明子进程结束了,waitpid也成功了,此时返回值就是子进程的pid ,跳出循环
在这里插入图片描述
子进程一共执行五秒后才退出,以非阻塞等待的模式,父进程就可以把这五秒拿去做其他事情

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

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

相关文章

今日行情明日机会——20250509

上证指数今天缩量&#xff0c;整体跌多涨少&#xff0c;走势处于日线短期的高位~ 深证指数今天缩量小级别震荡&#xff0c;大盘股表现更好~ 2025年5月9日涨停股主要行业方向分析 一、核心主线方向 服装家纺&#xff08;消费复苏出口链驱动&#xff09; • 涨停家数&#xf…

单片机-STM32部分:10、串口UART

飞书文档https://x509p6c8to.feishu.cn/wiki/W7ZGwKJCeiGjqmkvTpJcjT2HnNf 串口说明 电平标准是数据1和数据0的表达方式&#xff0c;是传输线缆中人为规定的电压与数据的对应关系&#xff0c;串口常用的电平标准有如下三种&#xff1a; TTL电平&#xff1a;3.3V或5V表示1&am…

RabittMQ-高级特性2-应用问题

文章目录 前言延迟队列介绍ttl死信队列存在问题延迟队列插件安装延迟插件使用事务消息分发概念介绍限流非公平分发&#xff08;负载均衡&#xff09; 限流负载均衡RabbitMQ应用问题-幂等性保障顺序性保障介绍1顺序性保障介绍2消息积压总结 前言 延迟队列介绍 延迟队列(Delaye…

React 播客专栏 Vol.5|从“显示”到“消失”:打造你的第一个交互式 Alert 组件!

&#x1f44b; 欢迎回到《前端达人 播客书单》第 5 期&#xff08;正文内容为学习笔记摘要&#xff0c;音频内容是详细的解读&#xff0c;方便你理解&#xff09;&#xff0c;请点击下方收听 &#x1f4cc; 今天我们不再停留在看代码&#xff0c;而是动手实现一个真正的 React…

解密火星文:LeetCode 269 题详解与 Swift 实现

文章目录 摘要描述题解答案题解代码分析构建图&#xff08;Graph&#xff09;拓扑排序&#xff08;Topological Sort&#xff09; 示例测试及结果时间复杂度空间复杂度实际场景类比总结 摘要 这篇文章我们来聊聊 LeetCode 269 题&#xff1a;火星词典&#xff08;Alien Dictio…

动态规划-62.不同路径-力扣(LeetCode)

一、题目解析 机器人只能向下或向左&#xff0c;要从Start位置到Finish位置。 二、算法原理 1.状态表示 我们要求到Finish位置一共有多少种方法&#xff0c;记Finish为[i,j]&#xff0c;此时dp[i,j]表示&#xff1a;到[i,j]位置时&#xff0c;一共有多少种方法&#xff0c;满…

5月9号.

v-for: v-bind: v-if&v-show: v-model: v-on: Ajax: Axios: async&await: Vue生命周期: Maven: Maven坐标:

从 Git 到 GitHub - 使用 Git 进行版本控制 - Git 常用命令

希望本贴能从零开始带您一起学习如何使用 Git 进行版本控制&#xff0c;并结合远程仓库 GitHub。这会是一个循序渐进的指南&#xff0c;我们开始吧&#xff01; 学习 Git 和 GitHub 的路线图&#xff1a; 理解核心概念&#xff1a;什么是版本控制&#xff1f;Git 是什么&…

双指针算法详解(含力扣和蓝桥杯例题)

目录 一、双指针算法核心概念 二、常用的双指针类型&#xff1a; 2.1 对撞指针 例题1&#xff1a;盛最多水的容器 例题2&#xff1a;神奇的数组 2.2 快慢指针&#xff1a; 例题1&#xff1a;移动零 例题2&#xff1a;美丽的区间&#xff08;蓝桥OJ1372&#xff09; 3.总…

【网络编程】二、UDP网络套接字编程详解

文章目录 前言Ⅰ. UDP服务端一、服务器创建流程二、创建套接字 -- socketsocket 属于什么类型的接口❓❓❓socket 是被谁调用的❓❓❓socket 底层做了什么❓❓❓和其函数返回值有没有什么关系❓❓❓ 三、绑定对应端口号、IP地址到套接字 -- bind四、数据的发送和接收 -- sendto…

【应急响应】- 日志流量如何分析?

【应急响应】- 日志流量如何下手&#xff1f;https://mp.weixin.qq.com/s/dKl8ZLZ0wjuqUezKo4eUSQ

djinn: 3靶场渗透

djinn: 3 来自 <https://www.vulnhub.com/entry/djinn-3,492/> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23.243 3&#xff0…

VS Code配置指南:打造高效的QMK开发环境

VS Code配置指南&#xff1a;打造高效的QMK开发环境 前言 你是否曾为QMK固件开发环境的搭建而头疼不已&#xff1f;本文将手把手教你使用Visual Studio Code&#xff08;简称VS Code&#xff09;这款强大的代码编辑器来构建一个完美的QMK开发环境&#xff0c;让你的键盘固件开…

服务器多客户端连接核心要点(1)

刷题 服务器多客户端连接核心要点 多进程服务器 实现原理 fork子进程&#xff1a;每次accept新客户端后&#xff0c;调用fork创建子进程。独立处理&#xff1a;子进程负责与客户端通信&#xff08;如read/write&#xff09;&#xff0c;父进程继续监听新连接。 特点 隔离性…

Stagehand:AI驱动的下一代浏览器自动化框架

Stagehand 是一个结合了 AI 代理、AI 工具和 Playwright 的浏览器自动化框架。核心理念是&#xff1a;让自动化任务既可控又智能。与传统工具不同&#xff0c;Stagehand 不仅仅依赖 AI 代理的“黑箱操作”&#xff0c;而是通过与 Playwright 的深度结合&#xff0c;赋予开发者对…

爱普生FA-238在车身控制模块中的应用

在汽车智能化、电子化飞速发展的当下&#xff0c;车身控制模块&#xff08;BCM&#xff09;作为车辆的 “智能管家”&#xff0c;肩负着协调和控制众多车身功能的重任&#xff0c;从车门的解锁与锁定、车窗的升降&#xff0c;到车灯的智能点亮与熄灭&#xff0c;再到雨刮器的自…

【A2A】管中窥豹,google源码python-demo介绍

前言 A2A&#xff08;Agent2Agent&#xff09;是 Google 推出的一项新协议&#xff0c;旨在解决多智能体&#xff08;Multi-Agent&#xff09;系统中跨平台、跨组织协作的难题。它为 AI 代理之间的通信、协作和任务分工提供了一个统一的标准&#xff0c;可以类比为网页世界的 H…

004-nlohmann/json 快速认识-C++开源库108杰

了解 nlohmann/json 的特点&#xff1b;理解编程中 “数据战场”划分的概念&#xff1b;迅速上手多种方式构建一个JSON对象&#xff1b; 1 特点与安装 nlohmann/json 是一个在 github 长期霸占 “JSON” 热搜版第1的CJSON处理库。它的最大优点是与 C 标准库的容器数据&#xf…

Matlab实现CNN-BiLSTM时间序列预测未来

Matlab实现CNN-BiLSTM时间序列预测未来 目录 Matlab实现CNN-BiLSTM时间序列预测未来效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CNN-BiLSTM时间序列预测未来&#xff1b; 2.运行环境Matlab2023b及以上&#xff0c;data为数据集&#xff0c;单变量时间序…

C语言| sizeof(array)占多少字节

C语言| 数组名作为函数参数 sizeof(数组名); 可以求出整个数组在内存中所占的字节数。 被调函数Array_Sum()中&#xff0c;数组array使用sizeof会得到多少&#xff1f; 实参数组a占32字节&#xff0c;实参a传给形参array&#xff0c;只占4字节。 原因如下&#xff1a; 数组名做…