当前位置: 首页 > news >正文

Linux的奇妙冒险——进程pcb第二讲

进程控制

  • 一.fork函数初识
  • 二.进程替换
  • 三.进程常见问题
    • 1.退出码
    • 2.exit函数
  • 四.回收进程(进程等待)
    • 1.wait/waitpid方法
    • 2. 等待回收过程
    • 3.子进程status

一.fork函数初识

在这里插入图片描述
fork()函数用于创建一个新进程,这个新进程被称为子进程。它是由父进程调用并创建的。

调用fork()后,父进程和子进程会各自得到一个返回值:

子进程中返回0,父进程返回子进程id,出错返回-1

具体用法:
通过检查返回值,进程可以判断自己是父进程还是子进程,从而执行不同的代码逻辑。

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度

如下给一段代码,在fork前只有父进程再走,在fork后变成两个进程

在这里插入图片描述
运行结果:
在这里插入图片描述
需要知道的是子进程是父进程的副本,但两者是独立的进程,可以并行执行。在执行代码时运用了写时拷贝,即只有在子进程需要修改数据时,系统分配对应的内存空间并通过页表映射。
在这里插入图片描述

具体实现我们放在虚拟内存章节再谈。

fork的常规用法:

  • 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
  • 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数

二.进程替换

替换原理
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

常见的替换函数

在这里插入图片描述
在这里插入图片描述

这几个函数差异在于第二个参数,以l结尾的是多个参数代表命令行参数,以v结束则是命令行参数指针表。

  • l(list) : 表示参数采用列表
  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量
    在这里插入图片描述
    事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在man手册第3节。这些函数之间的关系如下图所示。

在这里插入图片描述

函数解释
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1
所以exec函数只有出错的返回值而没有成功的返回值。

做一个小实验通过进程替换执行pwd
在这里插入图片描述

六种方式皆可替换
在这里插入图片描述

三.进程常见问题

1.退出码

退出代码是程序在完成执行后返回给其调用者的数值代码。它用于指示程序执行是否成功或失败,以及在失败的情况下提供有关失败原因的一些信息。

通常情况下,退出代码为 0 表示程序成功完成执行,而任何非零值则表示程序在执行过程中遇到了某种错误。不同的非零退出代码可以表示不同类型的错误。
在这里插入图片描述
通过echo $?可以查到上一条命令的退出码
在这里插入图片描述

2.exit函数

#include <unistd.h>
void _exit(int status);
参数:status 定义了进程的终⽌状态,⽗进程通过wait来获取该值

exit最后也会调⽤_exit, 但在调⽤_exit之前,还做了其他⼯作:

  1. 执⾏⽤户通过 atexit或on_exit定义的清理函数。
    比特就业课
  2. 关闭所有打开的流,所有的缓存数据均被写⼊
  3. 调⽤_exit

return 退出:
return是⼀种更常⻅的退出进程⽅法。执⾏return n等同于执⾏exit(n),因为调⽤main的运⾏时函数会将main的返回值当做 exit的参数。

四.回收进程(进程等待)

1.wait/waitpid方法

在这里插入图片描述

  • 1.pid=-1,等待任⼀个⼦进程。与wait等效。
    pid>0.等待其进程ID与pid相等的⼦进程。
  • 2.status: 输出型参数
    WIFEXITED(status): 若为正常终⽌⼦进程返回的状态,则为真。(查看进程是否是正常退出)
    WEXITSTATUS(status): 若WIFEXITED⾮零,提取⼦进程退码。(查看进程的退出码)
  • 3.options:默认为0,表⽰阻塞等待,WNOHANG: 若pid指定的⼦进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该⼦进程的ID。

2. 等待回收过程

在这里插入图片描述

  • 如果⼦进程已经退出,调⽤wait/waitpid时,wait/waitpid会⽴即返回,并且释放资源,获得⼦
    进程退出信息。

  • 如果在任意时刻调⽤wait/waitpid,⼦进程存在且正常运⾏,则进程可能阻塞。

  • 如果不存在该⼦进程,则⽴即出错返回

3.子进程status

wait和waitpid,都有⼀个status参数,该参数是⼀个输出型参数,由操作系统填充。
• 如果传递NULL,表⽰不关⼼⼦进程的退出状态信息。
• 否则,操作系统会根据该参数,将⼦进程的退出信息反馈给⽗进程。
• status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16⽐特位)

status 主要告诉我们两件事之一:

1.进程是如何终止的? (正常退出还是被信号杀死?)

2.它的退出码(Exit Code)或导致其终止的信号(Signal)是什么?
在这里插入图片描述
在具体获得退出码和终止信号时,我们可以采用系统提供的宏函数
WIFEXITED(status)

#define WIFEXITED(status)  (((status) & 0x7F) == 0)
// 0x7F 的二进制是 01111111,与 status 进行按位与操作后,
// 可以提取出低7位。如果结果为0,则正常退出。

WEXITSTATUS(status)

#define WEXITSTATUS(status)  (((status) >> 8) & 0xFF)
// 1. (status >> 8): 将 status 右移 8 位,使高8位移动到低8位的位置。
// 2. & 0xFF: 与 0xFF(二进制 11111111)进行按位与操作,确保只取这8位,屏蔽掉其他可能的高位。
http://www.lryc.cn/news/626637.html

相关文章:

  • 云原生俱乐部-k8s知识点归纳(5)
  • SpringTask入门
  • 关于多个el-input的自动聚焦,每输入完一个el-input,自动聚焦到下一个
  • Rust并发编程:解锁高性能系统的密钥
  • 第12课_Rust项目实战
  • 批处理指令常见问题
  • 软考高级--系统架构设计师--案例分析真题解析
  • 【clion】cmake脚本1:调试脚本并构建Fargo项目win32版本
  • 无需驱动!单文件实现键盘按键禁用的技术方案
  • 使用Jmeter轻松实现AES加密测试
  • 01-Docker概述
  • 云计算学习100天-第26天
  • FreeRTOS入门知识(任务通知(二)以及定时器浅析)(七)
  • 2025年8月技术问答第2期
  • AI 与 OCR 识别:深度融合的智能信息提取技术
  • Cobbler 自动化部署服务介绍与部署指南
  • 微服务自动注册到ShenYu网关配置详解
  • 亚矩阵:跨境卖家 YouTube 私域矩阵搭建的高效解决方案
  • 使用acme.sh自动申请AC证书,并配置自动续期,而且解决华为云支持问题,永久免费自动续期!
  • 5.k8s控制器-Replicaset-Deployment、pod 反亲和性
  • 基于截止至 2025 年 6 月 4 日,在 App Store 上进行交易的设备数据统计,iOS/iPadOS 各版本在所有设备中所占比例详情
  • 宿主机与容器通过 rmw_cyclonedds_cpp中间件进行ros2结点之间的通讯的相关注意事项
  • Gin自定义Error中间件
  • synchronized锁,ReentrantLock 锁
  • 路由器NAT的类型测定
  • ios八股文 -- Objective-c
  • 机器翻译 (Machine Translation) 经典面试笔试50题(包括详细答案)
  • 游戏本不插电源适配器不卡设置教程
  • 面试 TOP101 二分查找/排序专题题解汇总Java版(BM17 —— BM22)
  • TENON AI-AI大模型模拟面试官