【Hello Linux】进程概念
作者:@小萌新
专栏:@Linux
作者简介:大二学生 希望能和大家一起进步!
本篇博客简介:简单介绍下进程的概念
进程
- 基本概念
- PCB 程序控制块
- task_struct是什么
- task_struct里面有什么
- 查看进程
- 通过系统目录查看进程
- 通过ps指令查看
- 获取程序的pid和ppid
- 通过fork函数创建进程
- 如何理解fork创建的子进程
- 如何让父子进程做不同的事
- 进程的状态
- 运行状态 R (run)
- 浅度睡眠状态 S (sleep)
- 深度睡眠状态 D (disk sleep)
- 暂停状态-T (stop)
- 僵尸状态 Z(zombie)
- 死亡状态 X (dead)
- 僵尸进程
- 僵尸进程的危害
- 孤儿进程
基本概念
在操作系统的书本上一般这样子解释一个进程
进程(Process):是操作系统进行资源分配的最小单位。一个进程是一个程序的一次执行过程。
可是这到底是什么意思呢?
进程和程序又有什么区别呢?
下面我们先用一张图来解释进程和程序的区别
我们可以看到程序首先以文件的形式保存在磁盘当中 我们双击之后加载到了内存中 由cpu加载开始运行
这个进程被加载到内存之后我们可以看到除了原本的代码之外还多了一堆的数据
还记得我们之前的说操作系统是怎么管理的嘛? 先描述 再组织
这一堆多出来的数据就是操作系统对于进程的描述 而我们将这一堆数据称为PCB(Process Control Block) 程序控制块
那么到这里就可以回答上面的问题的
进程等于程序加上PCB
PCB 程序控制块
我们上面讲过 PCB是操作系统对于进程的描述
当我们使用ps指令的时候 我们可以看到系统中存在着大量的进程
同样的 每个进程都对应着一个PCB
我们可以这样理解
每个PCB对应着一个进程的数据 它们之间使用双链表组织起来 我们可以通过PCB来找到并管理每个进程
这样子我们就把操作系统对于进程的管理转化为了对于双链表的增删查改
task_struct是什么
进程控制块(PCB)的作用是描述进程的 而Linux系统是使用c语言写出来的
我们在c语言中一般是使用一个结构体去描述一个对象 这个在linux描述进程的结构体我们就把它叫做 task_struct
task_struct和PCB的关系就像是你和程序员 task_struct是PCB
task_struct一般会被储存在内存中
task_struct里面有什么
task_struct里面包含以下信息
- 标示符: 描述本进程的唯一标示符 用来区别其他进程
我们可以将它理解为学号
- 状态: 任务状态 退出代码 退出信号等
我们可以将这个理解为 正常上学 休学中等等
- 优先级: 相对于其他进程的优先级
- 程序计数器(pc): 程序中即将被执行的下一条指令的地址
- 内存指针: 包括程序代码和进程相关数据的指针 还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据
上下文数据的概念十分重要 下面我会使用一个小故事来帮助理解
假设你们现在学校有几个征兵名额 你被选上了 可以去当一年的兵然后回来继续学业 那你能直接过去然后一年后直接回来嘛? 显然是不可以的 如果这样子做你会发现一年后你被勒令退学了 为什么呢? 因为你事先没有给学校打招呼啊 学校以为你旷课旷了一整年 所以说你需要先向学校报备下情况之后才能去服役 这样子回来才能够继续学业 这就是上下文信息
- I/O状态信息: 包括显示的I/O请求 分配给进程的I/O设备和被进程使用的文件列表
- 记账信息: 可能包括处理器时间总和 使用的时钟总和 时间限制 记账号等
因为cpu执行进程的时候要保证尽量的公平 一个进程执行了很久了 那么就需要提高另外一个进程的优先级 那么执行多久这个信息保存在哪里呢?就是在 task_struct 中的记账信息中
- 其他信息
查看进程
我们可以通过两种方式来查看进程
- 通过系统目录查看
- 通过ps指令查看
通过系统目录查看进程
我们在根目录下可以找到一个叫做proc的目录
这个目录中含有大量的进程信息
我们可以发现 这些文件中有些是用数字表示的
而这些数字实际上就是程序的pid
如果我们想要查看这些进程的信息只需要进入里面就好了
通过ps指令查看
我们可以通过ps指令去查看进程
但是我们一般查看进程的时候使用的是这样子的语句
ps axj | head -1 && ps axj | grep 66
这段命令分为两部分
&& 连接的两个命令 如果前面执行成功了就会执行后面的语句
ps axj | head -1
这段命令的意思打出 ps axj的第一行
ps axj | grep 66
这段命令的意思是打出所有包含66的进程
获取程序的pid和ppid
- pid : pid是程序的标识符
- ppid: ppid是当前进程的父进程的标识符
我们可以写出一段代码来实验下
其中getpid() 的程序存放在 unistd.h 头文件里面
之后我们写好这段代码的makefile文件
之后使用make命令生成可执行程序
运行之后我们就可以发现该进程在循环打印子进程和父进程的pid
通过fork函数创建进程
fork是一个系统调用级别的函数 其功能就是创建一个子进程
我们可以通过如下的代码来验证它
我们的代码中只写了一行打印子进程和父进程的代码
make之后看看执行结果
我们可以发现明明只有一行代码 而这个代码却执行了两次
并且如果仔细观察我们还能发现这样子的规律
一个进程的pid是另外一个进程的ppid 这就是fork的作用
如何理解fork创建的子进程
- 从创建层面 不论是使用指令 跑代码还是使用fork创建进程 在操作系统眼中都没有区别
- 从继承层面 fork出来的子进程它本身没有代码和数据 所以说它是拷贝的父进程的代码和数据
那么代码和数据是全部拷贝过来吗?
对于代码来说 是的 但是一般创建进程之前的代码是用不到的 因为已经运行到创建进程结束了
对于数据来说父子进程的数据也就是PCB大部分是共享的 但是我们也要考虑修改的情况
因为进程相对来说具有独立性 比如说我们想让父进程返回一个10 子进程返回一个20 如果说他们完全共享一个PCB是无法做到的
这里就要用到一个写时拷贝的技术
如何让父子进程做不同的事
父子进程是共享同一段代码的 也就是说他们能做的事情是相同的
但是如果它们只能做相同的事情我们只需要使用循环语句就好了 根本没有必要大费周章来书写一个子进程
事实上我们可以通过一个叫做pid的返回值来区分父子进程 从而达到同时进行两个任务的目的
fork函数的返回值:
我们上面说过了fork是一个函数 既然是函数那么他就有返回值
而fork的返回值是这样子的
- 如果子进程创建失败返回-1
- 如果子进程创建成功 在父进程中返回子进程的pid 在子进程中返回0
那么我们就可以利用这个返回值让父子进程做不同的事情
我们可以发现这是个if else语句
执行之后我们可以发现如下的结果
我们发现竟然if else两个语句都执行了
这就是两个进程同时运行的结果
在做业务的时候我们可以将里面的代码换成业务逻辑就可以了
进程的状态
在进程从创建到消亡的这段时间会存在不同的状态 这些状态值储存在PCB当中 操作系统会根据PCB中的状态值来决定这个进程是否该运行了是否该结束了
一般来说 常见的进程状态有以下几点
在我们的linux源码中对于状态有着如下的定义
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char *task_state_array[] = {"R (running)", /* 0*/"S (sleeping)", /* 1*/"D (disk sleep)", /* 2*/"T (stopped)", /* 4*/"T (tracing stop)", /* 8*/"Z (zombie)", /* 16*/"X (dead)" /* 32*/
};
我们可以通过ps axj来查看进程的状态
运行状态 R (run)
一个进程处于运行状态(running) 并不意味着进程一定处于运行当中,运行状态表明一个进程要么在运行中 要么在运行队列里 也就是说 可以同时存在多个R状态的进程
浅度睡眠状态 S (sleep)
一个进程处于浅度睡眠状态(sleeping) 意味着该进程正在等待某件事情的完成 处于浅度睡眠状态的进程随时可以被唤醒 也可以被杀掉
我们可以写出下面你的一段代码来验证
我们运行完之后让这个进程休眠30秒
我们可以发现该进程确实是在睡眠中的
此时我们可以使用ctrl + c 或者 kill -9 + pid 杀掉它
深度睡眠状态 D (disk sleep)
一个进程处于深度睡眠状态(disk sleep)表示该进程不会被杀掉 即便是操作系统也不行,= 只有该进程自动唤醒才可以恢复 该状态有时候也叫不可中断睡眠状态(uninterruptible sleep) 处于这个状态的进程通常会等待IO的结束
例如 某一进程要求对磁盘进行写入操作 那么在磁盘进行写入期间 该进程就处于深度睡眠状态 是不会被杀掉的 因为该进程需要等待磁盘的回复(是否写入成功)以做出相应的应答(磁盘休眠状态)
暂停状态-T (stop)
在Linux当中 我们可以通过发送SIGSTOP信号使进程进入暂停状态(stopped) 发送SIGSTOP信号可以让处于暂停状态的进程继续运行
还是用我们上面的代码举例
我们可以看到在外面发送了暂停信号了之后进程就进入了暂定状态
我们再对该进程发送SIGCONT信号 该进程就继续运行了
僵尸状态 Z(zombie)
当一个进程将要退出的时候 在系统层面 该进程曾经申请的资源并不是立即被释放 而是要暂时存储一段时间 以供操作系统或是其父进程进行读取 如果退出信息一直未被读取 则相关数据是不会被释放掉的 一个进程若是正在等待其退出信息被读取 那么我们称该进程处于僵尸状态(zombie)
僵尸状态的存在是必要的
因为如果该进程的申请的资源在其运行结束之后立即释放那么我们便不知道该进程完成的如何
要知道它完成的如何我们必须要它的调用者来接受它的返回值 在了解完毕之后才可以让这个进程终止
我们在写c语言代码的时候通常在最后加上一个返回值
int main()
{// ..return 0;
}
这个return的值实际上是返回给操作系统的
我们可以使用 echo $? 命令来查询上次命令的返回值
死亡状态 X (dead)
我们一般不能查询到进程的死亡状态 因为在进程死亡的那一瞬间该进程的所有资源将会被释放 该进程也不存在了 所以说我们看不到它
僵尸进程
处于僵尸状态的进程就叫做僵尸进程
我们可以人为的制造一个僵尸进程 具体操作就是让父进程一直运行 然后子进程退出 这样子的话子进程就一直无法将返回值传递给父进程 那么它就会一直处于僵尸状态
我们写出这样子的代码
之后查询子进程的pid
我们可以看到他的状态就变成了Z 僵尸状态
僵尸进程的危害
- 僵尸进程的退出状态必须一直维持下去 因为它要告诉其父进程相应的退出信息 可是父进程一直不读取 那么子进程也就一直处于僵尸状态
- 僵尸进程的退出信息被保存在task_struct(PCB)中 僵尸状态一直不退出 那么PCB就一直需要进行维护
- 若是一个父进程创建了很多子进程 但都不进行回收 那么就会造成资源浪费 因为数据结构对象本身就要占用内存
- 僵尸进程申请的资源无法进行回收 那么僵尸进程越多 实际可用的资源就越少 也就是说 僵尸进程会导致内存泄漏
孤儿进程
在Linux中的进程大多是父子关系 万一一个进程的子进程还没有结束但是他的父进程结束了 那么我们就称这个进程为孤儿进程
如果没有父进程来管理这个子进程那么他就会一直占用资源 所以说为了防止这种情况 我们设计了让1号init进程来领养这个进程
我们可以写出下面的代码来实验
我们之后可以发现
子进程的父进程变为了 1 (init进程)
相关文章:

【Hello Linux】进程概念
作者:小萌新 专栏:Linux 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:简单介绍下进程的概念 进程基本概念PCB 程序控制块task_struct是什么task_struct里面有什么查看进程通过系统目录查看进程通过ps指令查…...

Bunifu.UI.WinForms 6.0.2 Crack
Bunifu.UI.WinForms为 WinForms创建令人惊叹的UI Bunifu.UI.WinForms我们为您提供了现代化的快速用户界面控件。用于 WinForms C# 和 VB.NET 应用程序开发的完美 UI 工具 简单 Bunifu.UI.WinForms没有臃肿的特征。正是您构建令人惊叹的 WinForms 应用程序所需要的。只需拖放然…...

学习 Python 之 Pygame 开发魂斗罗(五)
学习 Python 之 Pygame 开发魂斗罗(五)继续编写魂斗罗1. 加载地图2. 修改角色尺寸和地面高度继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗(四)中,我们完成了角色的移动和跳跃还有射击,由…...

LeetCode 104. 二叉树的最大深度
LeetCode 104. 二叉树的最大深度 难度:easy\color{Green}{easy}easy 题目描述 给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3…...

pandas 中如何按行或列的值对数据排序?
在处理表格型数据时,常会用到排序,比如,按某一行或列的值对表格排序,要怎么做呢? 这就要用到 pandas 中的 sort_values() 函数。 一、 按列的值对数据排序 先来看最常见的情况。 1.按某一列的值对数据排序 以下面…...

「牛客网C」初学者入门训练BC139,BC158
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练 🔥座右铭:“不要等到什么都没有了,才下定决心去做” 🚀🚀🚀大家觉不错…...

【深度学习】线性回归、逻辑回归、二分类,多分类等基础知识总结
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言1. 线性回归2、逻辑回归3. 单层神经元的缺陷&多层感知机softmax 多分类最后再来一个 二分类的例子前言 入行深度学习快2年了,是时间好好总结下基础知识了.现…...

【MySQL】调控 字符集
一、 MySQL 启动选项 & 系统变量 启动选项 是在程序启动时我们程序员传递的一些参数,而 系统变量 是影响服务器程序运行行为的变量 1.1 启动项 MySQL 客户端设置项包括: 允许连入的客户端数量 、 客户端与服务器的通信方式 、 表的默认存储引擎 、…...

FME+YOLOV7写DNF自动刷图脚本
目录 前言 一、难点分析 二、实现流程 1.DNF窗口位置获取 2.获取训练数据 3.数据标注 4.数据格式转换 5.数据训练 5.刷图逻辑编写 前言 这是一篇不务正业的研究,首先说明,这不是外挂!这不是外挂!这不是外挂!这只是用a…...

Java语法面试题
多线程锁 Synchronized:一次只能被一个线程占有ReadWriteLock:被多个线程持有,写锁只能被一个线程占有ReentrantLock:一个线程的多个流程能获取同一把锁,就是可重入锁,即在一个线程中可以被重复的获取自旋锁…...

location
目录 匹配的目标 格式 匹配符号: 优先级 要表达不匹配条件,则用 if 实现 例子:根目录的匹配最弱 例子:区分大小写 和 不区分大小写 例子:以根开头 和 不区分大小写 例子:等号 匹配的目标 ng…...

简述RBAC模型
RBAC(Role-Based Access Control)模型是一种常用的访问控制模型,用于管理和控制用户对系统资源的访问权限。RBAC模型通过将用户分配给角色,并授予角色相应的权限,来实现安全的资源访问管理。 在RBAC模型中,…...

倒计时2天:中国工程院院士谭建荣等嘉宾确认出席,“警务+”时代来临...
近日伴随公安部、科技部联合印发通知,部署推进科技兴警三年行动计划(2023-2025年),现代科技手段与警务工作相结合的方式,正式被定义为未来警务发展的新趋势。 21世纪以来,随着科技的不断发展和创新…...

Python蓝桥杯训练:基本数据结构 [哈希表]
Python蓝桥杯训练:基本数据结构 [哈希表] 文章目录Python蓝桥杯训练:基本数据结构 [哈希表]一、哈希表理论基础知识1、开放寻址法2、链式法二、有关哈希表的一些常见操作三、力扣上面一些有关哈希表的题目练习1、[有效的字母异位词](https://leetcode.cn…...

MacOS 配置 Fvm环境
系统环境:MacOS 13,M1芯片 1. 安装HomeBrew: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" speed 2. 使用brew安装Fvm: brew tap leoafarias/fvm brew install fvm 3…...

Python小白入门- 01( 第一章,第1节) 介绍 Python 编程语言
1. 介绍 Python 编程语言 1.1 Python 是什么 Python 是一种高级的、解释型、面向对象的编程语言,具有简洁、易读、易写的语法特点。Python 由 Guido van Rossum 于 1989 年在荷兰创造,并于 1991 年正式发布。 Python 语言广泛应用于数据科学、Web 开发、人工智能、自动化测…...

高并发系统设计之缓存
本文已收录至Github,推荐阅读 👉 Java随想录 这篇文章来讲讲缓存。缓存是优化网站性能的第一手段,目的是让访问速度更快。 说起缓存,第一反应可能想到的就是Redis。目前比较好的方案是使用多级缓存,如CPU→Ll/L2/L3→…...

【N32WB03x SDK使用指南】
【N32WB03x SDK使用指南】1. 简介1.1 产品简介1.2 主要资源1.3 典型应用2. SDK/开发固件文件目录结构2.1 doc2.2 firmware2.3 middleware2.4 utilities2.5 projects Projects3. 项目配置与烧录3.1 编译环境安装3.2 固件支持包安装3.3 编译环境配置3.4 编译与下载3.5 BLE工程目录…...

pytest测试框架——pytest.ini用法
这里写目录标题一、pytest用法总结二、pytest.ini是什么三、改变运行规则pytest.inicheck_demo.py执行测试用例四、添加默认参数五、指定执行目录六、日志配置七、pytest插件分类八、pytest常用插件九、改变测试用例的执行顺序十、pytest并行与分布式执行十一、pytest内置插件h…...

KAFKA安装与配置(带Zookeeper)2023版
KAFKA安装与配置(带Zookeeper) 一、环境准备: Ubuntu 64位 22.04,三台 二、安装JDK1.8 下载JDK1.8,我这边用的版本是jdk1.8.0_2022、解压jdk tar -zxvf jdk1.8.0_202.tar.gz 3、在/usr/local创建java文件夹,并将解压的jdk移动到/usr/local/java sudo mv jdk1.8.0_202…...

深入浅出解析ChatGPT引领的科技浪潮【AI行研商业价值分析】
Rocky Ding写在前面 【AI行研&商业价值分析】栏目专注于分享AI行业中最新热点/风口的思考与判断。也欢迎大家提出宝贵的意见或优化ideas,一起交流学习💪 大家好,我是Rocky。 2022年底,ChatGPT横空出世,火爆全网&a…...

.net 批量导出文件,以ZIP压缩方式导出
1. 首先Nuget ICSharpCode.SharpZipLib <script type"text/javascript">$(function () {$("#OutPutLink").click(function () { // 单击下文件时$.ajax({ // 先判断条件时间内没有文件url: "/Home/ExistsFile?statTime" $(&q…...

数据分析:某电商优惠卷数据分析
数据分析:某电商优惠卷数据分析 作者:AOAIYI 专栏:python数据分析 作者简介:Python领域新星作者、多项比赛获奖者:AOAIYI首页 😊😊😊如果觉得文章不错或能帮助到你学习,可…...

性能测试流程
性能测试实战一.资源指标分析1.判断CPU是否瓶颈的方法2.判断内存是否瓶颈的方法3.判断磁盘I/O是否瓶颈的方法4.判断网络带宽是否是瓶颈的方法二.系统指标分析三.性能调优四.性能测试案例1.项目背景2.实施规划(1)需求分析(2)测试方…...

zookeeper集群的搭建,菜鸟升级大神必看
一、下载安装zookeeperhttp://archive.apache.org/dist/zookeeper/下载最新版本2.8.1http://archive.apache.org/dist/zookeeper/zookeeper-3.8.1/二、上传安装包到服务器上并且解压,重命名tar -zxvf apache-zookeeper-3.8.1-bin.tar.gzmv apache-zookeeper-3.8.1-b…...

C语言之习题练习集
💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 文章目录牛客网题号: JZ17 打印从1到最大的n位数牛客网题号&#x…...

Buuctf [ACTF新生赛2020]Universe_final_answer 题解
1.程序逻辑 程序逻辑并不复杂: 首先输入字符串,然后对字符串进行一个判断是否满足条件的操作 如果满足则对字符串进行处理并输出,输出的就是flag 2.judge_860函数 显然根据这十个条件可以通过矩阵解线性方程组,这里对变量的命名做了一些调整,让Vi对应flag[i]方便读 …...

【Linux】环境变量
目录背景1.概念2.常见环境变量2.1 PATH指令和自定义程序向环境变量PATH中添加路径删除PATH中的路径2.2 env:显示所有环境变量2.3 环境变量相关的命令3.通过代码获取环境变量1.char* envp[]2.第三方变量enciron3.getenv函数获取指定环境变量4.利用获取的环境变量自制…...

单一职责原则
单一职责原则: 就一个类而言,应该只有一个引起它变化的原因,如果一个类承担的职责过多就等于把这些职责耦合在一起,至少会造成以下两方面的问题: 我们要去修改该类中的一个职责可能会影响到该类的其它职责。这种耦合…...

golangの并发编程(GMP模型)
GMP模型 && channel1. 前言2. GMP模型2.1. 基本概念2.2. 调度器策略2.3. go指令的调度流程2.4. go启动周期的M0和G02.5. GMP可视化2.6. GMP的几种调度场景3. channel3.1. channel的基本使用3.2. 同步器1. 前言 Go中的并发是函数相互独立运行的体现,Gorouti…...