【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,否则根…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
