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

news2024/9/30 14:44:00

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.coloradmin.cn/o/2179881.html

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

相关文章

奔三理工男适合转行做AI算法工程师吗?

奔三男生转行可以做什么&#xff1f; 干了几年开发程序员却面临降薪优化&#xff1f; 说实话&#xff0c;如果学历一般技术一般&#xff0c; 无法与时俱进的话&#xff0c;会容易面临尴尬情况…… 就业这件事&#xff0c;选对赛道方向至关重要&#xff01;&#xff01; 这…

profinet转ethercat连接伺服在工业现场的配置案例

在工业通信领域&#xff0c;Profinet 转 EtherCAT 网关的应用为实现不同工业网络之间的通信提供了有效的解决方案。以下是一个关于 Profinet 转 EtherCAT 网关链接伺服配置的案例。 首先&#xff0c;我们需要准备好相关的硬件设备&#xff0c;包括 Profinet 转 EtherCAT 网关、…

Docker Desktop 安装Centos 7.9 使用yum install不可用问题

安装centos镜像并run之后&#xff0c;使用yum install 命令安装出现如下错误&#xff0c;可使用此命令替换mirror。 报错信息&#xff1a; Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archaarch64&repoos&infracontainer error was…

2024第八届御网杯信息安全网络大赛线上WP详解(misc+cryoto)(详解-思路-脚本)

芜湖~ 首届御网杯线上和ISCC分开进行 但还是用的ISCC的页面差评 嘻嘻 又是玄乎的一天 以下是我自己的一些思路和解析 有什么问题或者建议随时都可以联系我 目录 附件 # Misc ##Notice ##编码转换 Brainfuck编码 jsfuck编码 Ook! 编码 ##bluetooth 导出压缩包 第一…

OpenGL 使用离屏渲染技术进行截图

文章目录 背景第三方库注意参考资料 一、离屏渲染&#xff08;一&#xff09;帧缓冲与帧缓冲对象&#xff08;FBO&#xff09;&#xff08;二&#xff09;附件&#xff08;Attachment&#xff09; 二、具体代码&#xff08;一&#xff09;主线程创建OpenGL窗口&#xff08;二&a…

python画图|自制渐变柱状图

在前述学习过程中&#xff0c;我们已经通过官网学习了如何绘制渐变的柱状图及其背景。 掌握一门技能的最佳检验方式就是通过实战&#xff0c;因此&#xff0c;本文尝试做一些渐变设计。 前述学习记录可查看链接&#xff1a; Python画图|渐变背景-CSDN博客 【1】柱状图渐变 …

CORE 中间件、wwwroot

ASP.NET Core中间件组件是被组装到应用程序管道中以处理HTTP请求和响应的软件组件&#xff08;从技术上来说&#xff0c;组件只是C&#xff03;类&#xff09;。 ASP.NET Core应用程序中的每个中间件组件都执行以下任务。 选择是否将 HTTP 请求传递给管道中的下一个组件。这可…

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

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

红日靶机(二)笔记

红日靶机二 环境搭建 只需要把虚拟机的 host-only&#xff08;仅主机&#xff09;网卡改为 10.10.10.0 网段&#xff0c;如下配置 把 NAT 网卡&#xff0c;改为 192.168.96.0 网段&#xff0c;如下 首先恢复到 v1.3 快照 让后点击放弃&#xff0c;放弃后再开机&#xff0c;用…

论文写作工具推荐小渡ai,MedSci,Open Access Library

1、知网作为写过论文或者即将要写论文的人&#xff0c;这个网站真的真的真的是你用的最多最多的网站。但是你一定不用自己充会员&#xff0c;因为你的学校肯定给你买了这个资料库&#xff0c;从学校图书馆的网页进去就行&#xff0c;或者你校外访问&#xff0c;就算是没有账号不…

【自动驾驶】控制算法(十一)深度解析车辆纵向控制 | 纵向双 PID 控制算法

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

心觉:如何重塑高效学习的潜意识(5)终结篇

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作184/1000天 上篇文章讲了如何发挥边学边用的威力及其底层逻辑 到此为止&#xff0c;我们已经系统地把“系统化学习”和“边学边用…

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

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

【北京迅为】《STM32MP157开发板嵌入式开发指南》- 第十五章 Linux 文件系统概念

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

Navicat 工具 下载安装

准备工作 下载 下载链接&#xff1a;http://localhost:8080 演示环境 操作系统&#xff1a;windows10 产品&#xff1a;Navicat 版本&#xff1a; 15.0.25 注意&#xff1a;如果需要其他版本可以自行下载。 安装步骤 1、解压&#xff08;如果解压中出现提示威胁要允许&#…

基于CNN+Transformer混合模型实现交通流量时序预测(PyTorch版)

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…

PHP程序如何实现限制一台电脑登录?

PHP程序如何实现限制一台电脑登录&#xff1f; 可以使用以下几种方法&#xff1a; 1. IP地址限制&#xff1a;在PHP中&#xff0c;可以通过获取客户端的IP地址&#xff0c;然后与允许登录的IP地址列表进行比对。如果客户端的IP地址不在列表中&#xff0c;就禁止登录。 “php $…

洛谷P1789MC生存插火把

洛谷P1789MC生存插火把 这道题有一个小坑&#xff0c;就是火把照亮的地方可能不在数组里&#xff0c;注意要把那一块地方去掉&#xff0c;这道题的出题者把范围都告诉我们了&#xff0c;大大滴降低了这道题的难度 下面是我的代码 #include <stdio.h>int n, m,k ;//一…

HarmonyOS Next系列之水波纹动画特效实现(十三)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…

基于ssm+vue的在线家用电器销售系统

摘要 本文介绍了一个基于SSM&#xff08;SpringSpring MVCMyBatis&#xff09;框架与Vue.js技术的在线家用电器销售系统。该系统旨在为用户提供便捷的家用电器购买体验&#xff0c;同时为商家提供一个高效的销售管理平台。系统前端采用Vue.js框架开发&#xff0c;实现了响应式布…