Linux相关概念和重要知识点(9)(父进程、子进程、进程状态)

1.父进程、子进程

(1)父进程

CLI本质上是一款命令行界面的软件,是用户调用接口层面的程序(上层,可以和系统调用接口做沟通),CLI和GUI是同级别的。用户的操作都是建立在CLI和GUI之上的。

但是CLI是一种界面类型的称呼,它实现的具体软件统称叫Shell(命令行解释器),所有的Shell都是命令行交互。为满足不同需求,Shell还有很多子类,他们有着不同的特点、指令、优势以满足不同用户的需求。其中bash就是Linux的Shell(命令行解释器),我们也可以说bash就是Linux的CLI。

当我们在Linux里登录之后,bash进程会最先加载(要满足用户的命令需求),因此它是我们用户登陆后最先出现的进程(它不是系统最父的进程,它本质也是systemd或init的子进程)进程的创建遵循树的结构,也就是bash是用户所有运行进程的父进程,每个子进程也可以创建自己的子进程。

当查看进程状态时,我们往往关注当前进程、它的子进程以及它的父进程,pid就是标志当前进程的标志,ppid就是标志其上一层的父进程的pid,我们也可以使用getppid()获取它,并查看它是谁。

运行起来是

我们可以看到,当我们用户直接启动程序时,是bash父进程分配一个子进程来帮助我们处理任务。也能看到bash进程也不过是一个当前用户的父进程而已,其pid也没什么特别的。事实上,每当我们打开一个用户,systemd或init都会创建一个新的bash为当前用户处理命令,同时成为用户下所有进程的父进程。

我们可以看到,我们打开了三个用户界面,自然需要三个bash进程来帮助我们处理命令行(时刻注意bash的本质是命令行解释器的进程,并且是因为它最早出现,所有进程都是在它的界面下启动的,因此才成为用户的父进程)

我们会注意到当我们启动./proc时,进程属性COMMAND那里显示./proc,COMMAND的意思是显示当前正在运行的进程对应的可执行程序的名称。因此我们grep bash查找到的就是正在运行bash程序的进程,也就是每个用户的最父进程。同时,因为这三个用户都是登录Shell创建的,所以前面有个-,显示为-bash。

总结:每当用户登录Shell时,Linux的systemd或init会自动创建一个专属的bash来提供命令行交互服务,同时因为其出现最早、用户的子进程都是在bash基础上创建的,所以每个bash充当对应用户的所有进程的父进程。进程的创建遵循树状结构,创建子进程是一种手段,其目的是为了保障父进程的安全(如果子进程出现问题,父进程不会直接受到影响,体现进程独立性),同时也分摊了任务,保证高效率完成

(2)创建子进程

按树状结构来讲,每个子进程都能创建自己的子进程。我们可以使用fork()来实现。fork()函数体内会自动帮我们创建一个子进程(代码数据 + PCB),之后运行起来。

fork()创建子进程并不会从磁盘中再拷贝一份代码和数据,而是从父进程那里拷贝。代码和父进程共享;数据单独保存一份,以实现进程与进程之间互不干扰,即独立性;PCB在拷贝的基础上稍加修改(如pid,ppid等属性)得到

结果是

我们发现,fork()函数体内部创建子进程之后,两个进程同时运行,当执行到return语句时已经是两个进程了,所以fork()能对应两个进程返回两个值,并且fork()根据自己的判断给子进程返回了0,给父进程返回了子进程的pid。这样父进程能够管理子进程,而子进程不需要关注太多,所以得到了0

我们还能验证父进程在fork()内创建子进程时,共享代码,独立数据,因此父进程的count一直没变,而子进程的一直在变。我们要深刻体会多进程的特点,就是各走各的(独立性),根据自己进程的数据来进行代码逻辑判断,互不干扰,所以你会发现两个while都能被执行,这在单进程里是不可能的。在多进程中,对于父进程,它在第一个while判断不成立,第二个成立,进入第二个while;对于子进程,第一个while就成立,所以执行。通过它们打印的信息,我们也能看出子进程的父进程就是创建它的那个进程,即子进程可以创建子进程,自己变成父进程。

我们进一步还能发现子进程和父进程的执行顺序其实不完全规律,有的时候一个进程连续执行多次。这是因为子进程PCB链入执行队列struct runqueue之后,调度器会通过管理runqueue来管理PCB。CPU调度器引入时间片保证尽量公平处理进程(OS自主决定),但不会绝对公平。

2.进程的状态

(1)操作系统进程的状态

在所有操作系统中,进程的状态主要分为如下几种,在不同操作系统中有些许不同。

创建:PCB + 代码和数据;就绪:创建好的进程链入调度队列(struct runqueue);运行:调度器将PCB交给CPU执行;阻塞:运行时有事件发生(I/O请求,等待竞争资源);终止:进程任务完成

①就绪、运行状态

struct runqueue队列包含int nums、PCB等。当CPU要执行时,调度器直接找struct runqueue,执行一个进程之后再链接到队尾,这是基于队列先进先出(FIFO)的原则以及根据时间片切换进程才实现的。在有的操作系统中,就绪状态和运行状态统称为运行状态,因为只要是在runqueue中,都意味着进程时刻会被调度器调度。

②阻塞状态

操作系统要管理底层的硬件,根据先描述,再组织的原则,内存中会创建struct device描述不同设备以及属性,struct device之间用数据结构联系起来,最后以struct devices*作为管理接口,OS通过对struct devices*的管理实现对硬件的管理。

每个struct device里面有一项成员变量PCB* wait_queue,当CPU处理时获得I/O请求时,调度器就会将整个PCB从struct runqueue中拿出来,通过PCB* wait_queue链入到要进行I/O操作的设备的struct deveice中。这样整个进程都被阻塞了,如果是代码也不会继续执行了,因为CPU需要进程的PCB才能操作,而此时PCB在设备队列里。运行状态和阻塞状态的本质区别就是PCB链入的队列不同。在进程阻塞时,CPU仍可以继续执行其他runqueue里面的进程而不受影响。

当I/O设备相应将数据写入或读取后(要成功读取完或写入完才行,而不只是响应),OS就会通过struct devices*得到信息(操作系统是硬件管理者),再次将PCB移回runqueue,此时进程的状态再次被切换为运行状态。

注意每次进程状态切换时,PCB内部的相应成员变量的值就会变,不同值对应不同进程状态,OS通过这个值能正确判断进程的状态,进而实现不同操作。

所以每次进行scanf时,就能看到进程被卡住了。对于连续几百行printf而言,我们则几乎看不到运行状态,因为CPU处理速度太快了,缓冲区能瞬间写满(内存相对较快),大部分时间PCB都是在阻塞状态等待硬件响应并将缓冲区的数据写入硬件(硬盘相对较慢)。

③阻塞挂起状态

当内存资源严重不足时,由于进程在阻塞期间CPU不调度,这个时候操作系统会把进程的对I/O无影响的代码和数据换出到磁盘里(进程 = PCB + 代码和数据,PCB保持不变);当I/O完成后更改状态,并把磁盘的代码和数据换入到内存里,再将PCB从struct device链入runqueue。硬盘中专门存储换出数据的磁盘分区叫swap分区。这种进程的状态叫阻塞挂起状态,是在阻塞的前提下将代码和数据换出到swap。

运行时挂起风险大,OS一般没开启。挂起状态 + swap分区是用时间换空间,swap分区不大,可以在装系统时自定义。云服务器上一般会禁掉swap分区,大型企业的空间比时间宝贵,因此要么优化软件要么买硬件。

阻塞挂起进程终归是一个紧急处理办法,它只能缓解当前操作系统内存紧缺的问题。在内存紧缺到一定程度时,OS会选择直接杀掉一些进程,OS会优先保证自己安全。

(2)Linux的进程状态

①R(running)运行状态:只要PCB在runqueue里都属于运行状态

在STAT那里,我们可以看到R状态,其中R+的加号表示前台程序当前台程序运行时,命令行解释器无法正常执行其它指令,就像Windows的前台任务那样,一次只能执行一个。

我们可以使用Ctrl + c来杀掉前台进程。除此之外,使用kill我们有更多管理进程的选项,其中kill -9 pid就是强制杀掉进程(包括前台和后台),kill -l可以查看选项

②S(sleeping)睡眠状态(阻塞状态,可中断睡眠,浅睡眠

当进入有多次连续I/O请求时,休眠状态就很频繁了,因为CPU将信息写入到内存缓冲区很快,但内存缓冲区满了就要刷新到显示器文件里,这个过程就很慢了,相较于内存读写至少慢了一个数量级。因此PCB大部分时间都是在等显示器响应并写入(写完了才会变成R+)在这种频繁打印的情况下就能看到S状态。

就算是S状态,它也依然是一个前台程序,前台程序运行过程中,我们的指令时无法执行的

③D(disk_sleep)磁盘睡眠状态(阻塞状态,不可中断睡眠,深度睡眠)

当有I/O请求时,PCB被列入磁盘等待队列struct device中等待响应和写入(读取),进程该状态为S,这似乎没什么问题。但是当操作系统资源严重不足时,挂起状态无法缓解内存不足时,操作系统为了自身安全有可能直接杀掉这种磁盘级别的I/O进程,这样就会导致数据丢失。

为了防止这种数据丢失,就有D状态,当进行磁盘级别的I/O时,PCB就会把自己的状态设置为D。当内存严重不足时,OS也会根据状态判断忽略状态为D的进程,转而去杀其它进程。这就像一个附身符一样。

只有在安装大型软件(几十或上百G)或者进行大量数据迁移时才会较长时间出现D,在日常使用中D状态几乎是瞬时的,硬盘只是相对内存慢,SSD的读写速度也能达到每秒几个G。

④T(stopped)暂停进程

暂停进程意味进程做了非法但不致命的操作,被OS暂停。我们可以自己人为暂停,本质上也是我们人为发现进程做了非法但不致命的操作才暂停的,如果真的致命了我们肯定也是杀进程。使用kill -19 pid即可让代码暂停执行。

kill -18 pid可以恢复(重启)进程,注意恢复不是从第一行代码开始执行,而是接着停下来的代码继续执行

T状态重启后进程的状态会发生改变,会由前台进程变为后台进程

这里的S没有加号可以印证这一点。这就像我们Windows里面的后台下载任务一样,前台被腾出了位置,我们的指令可以正常执行了。

我们甚至可以让前台任务和后台任务一起执行,也不会冲突

后台任务是不能通过Ctrl + c来杀掉的,它只能杀掉前台进程,我们只能用kill -9来帮我们强制杀进程

⑤t(tracing stop)追踪进程

我们要使用循环指令来监视追踪进程,其中while : ;do (指令) ;done可以实现

调试打断点的时候,进程就被设置为了跟踪进程,人们可以自己掌控代码的执行情况。

⑥Z(zombie)僵尸进程

子进程被父进程创建的原因是基于某种应用,为了完成某项任务。当子进程的任务完成后,它需要向父进程传递信息,告诉父进程子进程的任务完成的怎么样(进程的退出信息),父进程才可以即时调整安排。完成告诉父进程任务完成的怎么样的这个任务是由PCB来完成的。

创建进程时PCB先被创建,代码数据才被导入。在进程结束之际,代码数据先被OS回收,PCB最后被销毁。PCB先创建是为了能在数据代码导入后能第一时间管理。而PCB后回收则是为了保障PCB里存储的关于该任务完成情况的信息被父进程读走,而在PCB等待父进程读取信息之前,代码和数据就已经被释放了,这个阶段就叫僵尸进程。当进程进入Z状态后,严格上来说它已经不再是一个进程了(进程 = PCB + 代码和数据,缺一不可),Z状态的进程只是一个仅有PCB信息的躯壳,我们也无法kill掉一个已经进入Z状态的进程(进程本质上已经死了)。

new、malloc的堆区空间也叫代码和数据,只要进程进入Z状态,它就会直接被系统释放,并不会造成所谓内存泄漏。内存泄漏一般是指那些无法退出、需要长期运行的程序(如杀毒软件,常驻内存进程),对于那些进程而言如果不及时释放数据,确实会一直增加内存占用,但那种一跑起来就退的进程有点内存泄漏其实不影响。我们只关注常驻进程的内存泄漏

但现在的问题是强调僵尸进程的意义何在?

对于由系统父进程创建的子进程而言,Z状态基本上就是一瞬间的事,但对于我们自己创建的进程,情况就有些不一样了。

当我使得父进程陷入死循环,子进程结束时就会向父进程发送信号,而父进程处于大量I/O阻塞中,会错过信号,子进程的PCB就无法被读取,就会陷入Z状态。

这种情况下,子进程的PCB就无法被释放。PCB本身也是一个占用较大的结构体,这样的Z进程多了,也会造成计算机卡顿。<defunct>就标志着僵尸进程或死进程,这种进程无法通过kill删除掉(可以kill让子程序进入僵尸状态,因为它们已经死了。

这个时候只有对父进程进行管理才行

还有一种情况是父进程比子进程先结束

我们可以看到子进程的ppid变成了1,这是系统的systemd进程。当父进程比子进程先结束时,父进程会被直接回收,而子进程就会交给系统接管(systemd领养),这种进程称为孤儿进程,孤儿进程会退到后台运行

注意僵尸进程不会被systemd领养,因为僵尸进程是有父进程的,如果这时父进程结束,两个进程会一起回收,不会出现领养的情况

⑦X(dead)死进程

这个进程状态是一瞬间的,当PCB信息被读取后,就会进入X状态,OS会直接回收PCB。此时就标志一个进程彻底结束了。

echo $?可以获取最近一个进程退出时的信息,一般情况下0表示正常执行,非0表示出错

这个数字其实就是C语言main函数的返回值

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

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

相关文章

SPI驱动OLED

OLED像素发光原理 OLED-有机发光半导体&#xff0c;在有机高分子聚合物的两端施加电压可发光,LED基于金属硅片发光&#xff0c;而OLED可以附于玻璃、塑料&#xff0c;可以用OLED做出曲面屏折叠屏&#xff0c;不同于LCD&#xff0c;OLED没有背光板&#xff0c;每个像素可以独立…

墙绘产品展示:基于SpringBoot的解决方案

5 系统实现 系统实现部分就是将系统分析&#xff0c;系统设计部分的内容通过编码进行功能实现&#xff0c;以一个实际应用系统的形式展示系统分析与系统设计的结果。前面提到的系统分析&#xff0c;系统设计最主要还是进行功能&#xff0c;系统操作逻辑的设计&#xff0c;也包括…

scrapy 爬取微博(五)【最新超详细解析】: 爬取微博文章

1 读取配置参数 爬取微博文章首先需要读取settings.py中的设置的配置变量&#xff0c;然后编写爬虫&#xff0c;读取的配置变量主要有爬取的关键词、时间范围、爬取区域等。 class WeiboSearchSpider(scrapy.Spider):name weibo_searchallowed_domains [weibo.com]settings…

记一次J1900主板短路报废

记一次J1900主板短路报废 一、主板样貌 J1900的CPU&#xff0c;板载4GB内存&#xff0c;64GB固态&#xff0c;双千M&#xff0c;又HDMI。就是这个电源线&#xff0c;右上角是用线连接的。 二、缘由 前两天接了一个转接板&#xff0c;为了给新增的机械硬盘供电。上午刚测试…

演讲干货整理:泛能网能碳产业智能平台基于 TDengine 的升级之路

在 7 月 26 日的 TDengine 用户大会上&#xff0c;新奥数能 / 物联和数据技术召集人袁文科进行了题为《基于新一代时序数据库 TDengine 助力泛能网能碳产业智能平台底座升级》的主题演讲。他从泛能网能碳产业智能平台的业务及架构痛点出发&#xff0c;详细分享了在数据库选型、…

【最新华为OD机试E卷-支持在线评测】字符串分割转换(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

Flux 最新最快ControlNet模型现身:法线贴图详细测评

原文链接&#xff1a;Flux目前最快ControlNet模型现身&#xff01;法线贴图详细测评 (chinaz.com) Flux目前最快ControlNet模型现身&#xff01; 上周一个名叫JasperAI的团队开源了他们的 3 款Flux ControlNet&#xff0c;分别是法线贴图&#xff0c;深度&#xff0c;和升频器…

8608 实现二叉排序树的各种算法(2)

### 思路 1. **插入新结点**&#xff1a;在二叉排序树中插入新结点。 2. **遍历二叉树**&#xff1a;实现前序、中序、后序遍历。 3. **中序遍历的非递归算法**&#xff1a;使用栈实现中序遍历。 4. **层次遍历二叉树**&#xff1a;使用队列实现层次遍历。 5. **查找给定关键字…

【U8+】安装用友U8+16.5后,应用服务管理中缺少加密服务。

【问题描述】 安装用友U8+后,应用服务管理中,没有加密服务。 导致软件无法登录到加密服务器。 【解决方法】 此问题多为CPU所影响: 1、深信服和霆智虚拟机需要开启HOST CPU选项。不开启此选项无法发挥CPU的全部功能,对U8和SQL Server的性能影响很大,所以在U8V16.5中要求开…

排序算法之——归并排序,计数排序

文章目录 前言一、归并排序1. 归并排序的思想2. 归并排序时间复杂度及空间复杂度3. 归并排序代码实现1&#xff09;递归版本2&#xff09;非递归版本 二、计数排序1. 计数排序的思想2. 计数排序的时间复杂度及空间复杂度3. 计数排序代码实现 总结&#xff08;排序算法稳定性&am…

荣耀问鼎!宏山激光斩获2024年度行业创新大奖

8月28日&#xff0c;由高科技行业门户OFweek维科网主办的“维科杯OFweek2024激光行业年度评选”于中国深圳成功举办。宏山激光凭借出类拔萃的技术创新实力与卓越品质&#xff0c;成功斩获“维科杯OFweek2024年度激光行业最佳智能装备/自动化产线技术创新奖”。 这一殊荣绝非偶然…

RabbitMQ的应用问题

一、幂等性保障 幂等性是数学和计算机科学中某些运算的性质, 它们可以被多次应⽤, ⽽不会改变初始应⽤的结果 数学上的幂等性&#xff1a; f(x)f(f(x)) |x| 数据库操作幂等性&#xff1a; 数据库的 select 操作. 不同时间两次查询的结果可能不同, 但是这个操作是符合幂等性…

profinet转Ethernet网关在工业现场如何应用

一、项目背景 在某工业自动化系统中&#xff0c;现有的设备采用Profinet通信协议&#xff0c;而新引入的一些智能设备只支持Ethernet通信。为了实现不同协议设备之间的互联互通&#xff0c;决定采用开疆智能Profinet转Ethernet网关来解决通信兼容性问题。 二、硬件准备 1.支持P…

《C++》解密--单链表

目录 一、概念与结构 二、实现单链表 三、链表的分类 四、单链表算法题 一、概念与结构 1、节点 结点的组成主要有&#xff1a;当前结点要保存的数据和保存下一个节点的地址&#xff08;指针变量&#xff09; 图中指针变量plist保存的是第一个结点的地址&#xff0c;我们称p…

极限电流型氧传感器的工作原理以及有哪些应用场景?

极限电流型氧传感器的工作原理&#xff1a; 极限电流型氧传感器的工作原理基于稳定ZrO2固体电解质的氧泵作用。在已稳定化ZrO2两侧被覆铂电极&#xff0c;阴极侧用有气体扩散孔的罩接合&#xff0c;形成阴极空腔。在一定的温度下&#xff0c;当ZrO2电极两侧加一定电压时&#…

【渗透实战系列】|App渗透 ,由sql注入、绕过人脸识别、成功登录APP

涉及知识点 1、APP抓包和逆向破解加密算法&#xff1b; 2、解密参数&#xff0c;寻找注入点&#xff1b; 3、Union注入构造万能密码&#xff1b; 4、利用忘记密码功能&#xff0c;burpsuite爆破用户名&#xff1b; 5、解密短信验证数据包&#xff0c;绕过验证码&#xff0c;成功…

Docker笔记-Docker磁盘空间清理

无用的容器指的是已经停止运行且处于非活跃状态的容器。无用的镜像包括没有被任何容器使用的镜像&#xff0c;或者是被标记为"<none>"的镜像&#xff0c;通常是构建过程中产生的无标签镜像。 通过执行 docker container ls -a 和 docker image ls -a 命令&…

2024年软考——系统规划与管理师30天冲刺学习指南!!!

距离2024下半年软考系统规划与管理师考试已经只剩一个多月了&#xff0c;还没有开始备考的小伙伴赶紧行动起来。为了帮助大家更好的冲刺学习&#xff0c;特此提供一份考前30天学习指南。本指南包括考情分析、学习规划、冲刺攻略三个部分&#xff0c;可以参考此指南进行最后的复…

墙绘艺术在线交易平台:SpringBoot技术详解

4 系统设计 墙绘产品展示交易平台的设计方案比如功能框架的设计&#xff0c;比如数据库的设计的好坏也就决定了该系统在开发层面是否高效&#xff0c;以及在系统维护层面是否容易维护和升级&#xff0c;因为在系统实现阶段是需要考虑用户的所有需求&#xff0c;要是在设计阶段没…

【视频目标分割-2024CVPR】Putting the Object Back into Video Object Segmentation

Cutie 系列文章目录1 摘要2 引言2.1背景和难点2.2 解决方案2.3 成果 3 相关方法3.1 基于记忆的VOS3.2对象级推理3.3 自动视频分割 4 工作方法4.1 overview4.2 对象变换器4.2.1 overview4.2.2 Foreground-Background Masked Attention4.2.3 Positional Embeddings 4.3 Object Me…