【Linux】详谈 进程控制
目录
一、进程是什么
二、task_struct
三、查看进程
四、创建进程
4.1 fork函数的认识
4.2 2. fork函数的返回值
五、进程终止
5.1. 进程退出的场景
5.2. 进程常见的退出方法
5.2.1 从main返回
5.2.1.1 错误码
5.2.2 exit函数
5.2.3 _exit函数
5.2.4 缓冲区问题补充(为什么_exit不刷新缓冲区)
六、进程等待
6.1. wait和waitpid等待回收子进程
6.2 阻塞与非阻塞
Linux专栏:传送门!
一、进程是什么
在操作系统中,进程是资源分配和独立运行的基本单位。它是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。单纯的只看一个定义很难理解什么是进程

我们磁盘中的可执行程序,CPU要想拿到并且执行,代码和数据要先放在内存中。操作系统是一个软件在内存中,当磁盘中的可执行程序被内存拿到,可执行程序的代码和数据会被内存拿到,内存中的操作系统会对代码和数据进行描述然后组织为数据结构(先组织在描述)形成内核数据结构对象,对进程的管理就变成了对数据结构对象的增删查改。 内核数据结构对象可以称为PCB,也叫做进程控制块。
内核数据结构对象通过指针指向本身的代码和数据也指向下一个结构体,进而形成真正的进程。进程=内核数据结构对象+自己的代码和数据。 这个数据结构就是进程列表。CPU对进程列表进行调度。
二、task_struct
在Linux中描述进程的结构体叫做task_struct。
task_struct是Linux内核的⼀种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
三、查看进程
进程的信息可以通过/proc 系统文件夹查看
如:要获取PID为1的进程信息,你需要查看/proc/1 这个文件夹。
大多数进程信息同样可以使用top和ps这些用户级工具来获取
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{while(1){sleep(1);}return 0;
}
通过系统调用获取进程标示符
• 进程id(PID)
• 父进程id(PPID)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{printf("pid: %d\n", getpid());printf("ppid: %d\n", getppid());return 0;
}
四、创建进程
4.1 fork函数的认识
在linux中fork函数非常重要, 它从已存在的进程中创建一个新的进程, 新进程为子进程,而原进程为父进程。
#include<unistd.h>
pid_t fork(void);
返回值:子进程中返回0, 父进程中返回子进程id, 出现错误则返回-1
进程调用fork,当控制转移到内核中的fork代码后, 内核会做下面几件事情:
- 分配新的内存块和内核数据结构给子进程
- 将父进程部分数据结构内容拷贝至子进程
- 添加子进程到系统进程列表中
- fork返回, 开始调度器调度
当一个进程调用fork()之后,就有两个二进制代码相同的进程。而且他们都运行到相同的地方。但每个进程都将可以开始他们自己的旅程。
这里我们看到了三行输出, 一行before, 两行after,父进程先打印before消息,然后它又打印after,另一个after消息有子进程打印的,但是子进程没有打印before,为什么呢?
所以, fork()之前父进程独立执行,fork()之后,父子两个执行流分别执行,注意,fork之后,谁先执行由调度器决定。
4.2 2. fork函数的返回值
子进程返回0,父进程返回的是子进程的pid。
父进程与子进程是一对多的关系,父进程:子进程=1:N。对于子进程来说它只有一个父进程,对于父进程来说他有多个父进程。为了管理这些进程,所有父进程返回子进程的PID具有唯一性。子进程要想找到父进程肯定更方便。
为什么有两个返回值, 因为fork之后是两个不同的进程, 而返回值也是给不同的进程。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main() { pid_t pid = fork(); // 执行 fork() if (pid < 0) { // 处理 fork 失败的情况 perror("fork failed"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程执行 printf("This is the child process (PID: %d)\n", getpid()); } else { // 父进程执行 printf("This is the parent process (PID: %d, Child PID: %d)\n", getpid(), pid); } return 0; // 所有进程执行完毕
}
执行fork函数,会为子进程创建一个和父进程一样的PCB。但是他们所指向的代码都是一样的,所以他们的代码共享。也就是说父进程和子进程共享代码中return,都执行return。
五、进程终止
本质:释放系统资源, 就是释放进程申请的相关内核数据结构和对应的代码和数据。
5.1. 进程退出的场景
- 代码运行完毕, 结果正确
- 代码运行完毕,结果不正确
- 代码异常终止
5.2. 进程常见的退出方法
5.2.1 从main返回
除了main函数的返回值表示进程结束,其它函数的return都表示函数结束。
5.2.1.1 错误码
main函数的返回值是返回给父进程或者系统的,命令行中获取最近一个进程的返回值我们可以使用echo $?来获取
对于返回值,0表示成功, 非0表示错误,为什么会失败呢?系统提供了不同的错误码信息记录了错误的原因, 也可以自己约定错误码。
那么什么是错误码呢?
举个栗子:
如果想要查看错误码, 我们可以使用errno函数, 使用man可以查看命令详情。
man 3 errno
如果想知道具体的错误内容, 可以使用strerror函数,参数传递错误码。
man 3 strerror
5.2.2 exit函数
在代码的任何地方, 让进程直接结束。参数就是返回的错误码。
如果使用exit, 如果缓冲区有数据, 则会被刷新出来。
5.2.3 _exit函数
是系统层的进程终止调用
如果使用_exit, 缓冲区的数据则不会被刷新出来。
5.2.4 缓冲区问题补充(为什么_exit不刷新缓冲区)
exit属于是语言级别的,在三号手册, 而_exit是系统级别的,在二号手册。
_exit本质上是系统调用
所以我们上面的_exit实际上是绕过了语言层, 直接进行了系统调用, 而刚刚的缓冲区是语言级别的, fflush也是语言级别的。
六、进程等待
首先我们可以查看一下fork的返回值, 如果fork失败, 则错误码会被设置。
6.1. wait和waitpid等待回收子进程
一般而言, 父进程创建的子进程, 父进程就要等待子进程进行回收, 如果子进程一直不退出, 则父进程就会阻塞在wait内部。
wait的作用,等待任意的子进程(参数可以传nullptr表示不获取status)
常用:
waitpid的作用:第一个参数 pid>0表示等待指定的一个进程,pid == -1表示等待任意一个子进程
看一下他们的返回值, 如果等待成功则返回对应的子进程,如果等待失败则返回-1.
举个栗子:
等待任何一个子进程
当然, 我也可以修改id的参数,比如更换为刚刚子进程id,这里就不展示了。
waitpid的第二个参数,它会帮助父进程获取子进程的退出信息,通过参数的方式给我们带出来。输出型参数
但是这里的退出信息却是256,为什么不是1呢?
其实,status这个参数包含的信息并不只是退出码,它的本质是一个位图, 它的结构中前八位是退出状态,有256种状态 ,低七位是终止信号, 还有一个标志位。
如果想要提取退出状态则需要进行位运算,如下
小问题: 那我们可不可以不使用status来获取状态码,而是用一个全局变量呢?
不可以, 因为进程具有独立性,子进程修改父进程看不到,会发生写时拷贝。
6.2 阻塞与非阻塞
![]()
waitpid的第三个参数就是关于阻塞等待与非阻塞等待
首先waitpid的返回值, 如果>0表示,返回目标进程pid, 如果 == 0, 等待成功,但是子进程没有退出, <0 等待失败.
参数如果传0表示阻塞等待, 如果传WNOHANG表示非阻塞等待
举个栗子:

总结
进程控制是操作系统中的一个重要主题,主要涉及如何管理和调度进程以确保计算机系统的高效运行!
本篇完,下篇见!

相关文章:
【Linux】详谈 进程控制
目录 一、进程是什么 二、task_struct 三、查看进程 四、创建进程 4.1 fork函数的认识 4.2 2. fork函数的返回值 五、进程终止 5.1. 进程退出的场景 5.2. 进程常见的退出方法 5.2.1 从main返回 5.2.1.1 错误码 5.2.2 exit函数 5.2.3 _exit函数 5.2.4 缓冲区问题补…...
Linux top 命令
作用 top 是一个实时系统监控工具,用于查看系统的资源使用情况和进程状态。 示例 以下是一些常用的 top 命令示例: top :动态显示结果,每 3 秒刷新一次。 top -d 2:动态显示结果,每 2 秒刷新一次。 top …...
Leetcode 424-替换后的最长重复字符
给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后,返回 包含相同字母的最长子字符串的长度。 题解 可以先做LCR 167/Leetcode 03再做本题 滑动窗口&…...
《StyleDiffusion:通过扩散模型实现可控的解耦风格迁移》学习笔记
paper:2308.07863 目录 摘要 1、介绍 2、相关工作 2.1 神经风格迁移(NST) 2.2 解耦表示学习(DRL) 2.3 扩散模型(Diffusion Models) 3、方法 3.1 风格移除模块 3.2 风格转移模块 3.3 …...
Django 创建表时 “__str__ ”方法的使用
在 Django 模型中,__str__ 方法是一个 Python 特殊方法(也称为“魔术方法”),用于定义对象的字符串表示形式。它的作用是控制当对象被转换为字符串时,应该返回什么样的内容。 示例: 我在初学ModelForm时尝…...
图像处理之CSC
CSC 是 Color Space Conversion(色彩空间转换)的缩写,它涉及图像处理中的亮度、饱和度、对比度和色度等参数的调整。这些参数是图像处理中的核心概念,通常用于描述和操作图像的颜色信息。 以下是亮度、饱和度、对比度和色度与 CS…...
C语言数组之二维数组
C语言 主要内容 数组 二维数组 数组 二维数组 定义 二维数组本质上是一个行列式的组合,也就是说二维数组由行和列两部分组成,属于多维数组。二维数组数据是通过行列进行解读。二维数组可被视为一个特殊的一维数组,相当于二维数组又是一…...
PyTorch 源码学习:阅读经验 代码结构
分享自己在学习 PyTorch 源码时阅读过的资料。本文重点关注阅读 PyTorch 源码的经验和 PyTorch 的代码结构。因为 PyTorch 不同版本的源码实现有所不同,所以笔者在整理资料时尽可能按版本号升序,版本号见标题前[]。最新版本的源码实现还请查看 PyTorch 仓…...
vite+vue3开发低版本浏览器不支持es6语法的问题排坑笔记
重要提示:请首先完整阅读完文章内容后再操作,以免不必要的时间浪费!切记!!!在使用vitevue3开发unapp项目时,发现低版本浏览器不兼容es6的语法,如“?.” “??” 等,为了…...
C语言中printf()函数,格式输出符
在 C 语言中,printf() 函数的格式输出符(格式说明符)用于控制输出的格式和数据类型。以下是常见的格式说明符及其用法: 基本格式符 打印各种类型的值 格式输出符数据类型说明%dint输出有符号十进制整数%uunsigned int输出无符号…...
AI 编程工具—Cursor 进阶篇 数据分析
AI 编程工具—Cursor 进阶篇 数据分析 上一节课我们使用Cursor 生成了北京房产的销售数据,这一节我们使用Cursor对这些数据进行分析,也是我们尝试使用Cursor 去帮我们做数据分析,从而进一步发挥Cursor的能力,来帮助我们完成更多的事情 案例一 房产销售数据分析 @北京202…...
青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试
青少年编程与数学 02-009 Django 5 Web 编程 20课题、测试 一、软件测试二、自动化测试三、单元测试四、Django 单元测试(一)、创建测试用例(二)、运行测试(三)、常用测试功能 课题摘要: 本文全面介绍了软件…...
zookeeper watch
目录 回顾回调&观察者模式&发布订阅模式Zookeeper 客户端/ 服务端 watchgetChildren 为例最后归纳 回顾回调&观察者模式&发布订阅模式 回调的思想 类A的a()方法调用类B的b()方法类B的b()方法执行完毕主动调用类A的callback()方法 回调分为同步回调和异步回调…...
vue3.x 的shallowReactive 与 shallowRef 详细解读
在 Vue 3.x 中,shallowReactive 和 shallowRef 是两个用于创建浅层响应式数据的 API。它们与 reactive 和 ref 类似,但在处理嵌套对象时的行为有所不同。以下是它们的详细解读和示例。 1. shallowReactive 作用 shallowReactive 创建一个浅层响应式对…...
鸿蒙NEXT开发-界面渲染(条件和循环)
注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识 目录 1. 渲染-条件渲染 1.1 基本介绍 1.2 使…...
python电影数据分析及可视化系统建设
博主介绍:✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
在本地校验密码或弱口令 (windows)
# 0x00 背景 需求是验证服务器的弱口令,如果通过网络侧校验可能会造成账户锁定风险。在本地校验不会有锁定风险或频率限制。 # 0x01 实践 ## 1 使用 net use 命令 可以通过命令行使用 net use 命令来验证本地账户的密码。打开命令提示符(CMD࿰…...
pytest测试专题 - 1.3 测试用例发现规则
<< 返回目录 1 pytest测试专题 - 1.3 测试用例发现规则 执行pytest命令时,可以不输入参数,或者只输入文件名或者目录名,pytest会自己扫描测试用例。那pytest基于什么规则找到用例呢? 文件名:满足文件名称为tes…...
零基础学习人工智能
零基础学习人工智能是一个既充满挑战又极具潜力的过程。以下是一份详细的学习指南,旨在帮助零基础的学习者有效地踏入人工智能领域。 一、理解基本概念 在学习人工智能之前,首先要对其基本概念有一个清晰的认识。人工智能(AI)是…...
LeetCode热题100- 缺失的第一个正数【JavaScript讲解】
题目: 解题一: 如果不考虑时间复杂度和空间复杂度的话,我们最先想到的办法是先将该数组进行排序和去重,将最初的res结果值设置为1;将然后进行遍历,如果第一项不为1,则返回1,否则根…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
