广告公司网站建设方案,多久可以拿证,手机版网页游戏,贵阳网站开发外包引言#xff1a;
北京时间#xff1a;2023/2/17/8:17#xff0c;目前听着超能陆战队主题曲《Immortals》#xff0c;感觉又要螺旋式升天#xff0c;并且为我今天上午没课感到happy#xff0c;所以继我们很久以前的关于进程的博客#xff0c;今天我们就再来学习一下有关…引言
北京时间2023/2/17/8:17目前听着超能陆战队主题曲《Immortals》感觉又要螺旋式升天并且为我今天上午没课感到happy所以继我们很久以前的关于进程的博客今天我们就再来学习一下有关进程状态这一方面的知识让我们可以更好的理解硬件、操作系统和各种应用软件之间的关系和原理。 有关为什么学习Linux、Linux的指令权限、各种工具使用、操作系统等知识各位可以适当的复习一下哦这里我就不多加赘述了。进入主题
从系统操作看进程
一个程序的执行过程
磁盘中存放着我们的可执行文件后缀 .obj此时我们电脑中有一个可执行文件存储在磁盘中当我们双击运行此文件时我们的操作系统识别到此操作于是通过文件系统驱动找到此文件然后把此文件就给加载到了内存之中此时我们的可执行文件也就加载到了内存之中。当我们内存中的可执行文件被CPU调用然后经过CPU的计算和控制之后返回到内存并最终被我们的操作系统重新从内存中识别然后运行到我们电脑的其它硬件或软件之上此时我们才可以说我们形成了一个进程此时也就可以在我们的显示屏上的任务资源管理器上看到该进程了。
认识内存对pcbtask_struct的管理
通过上述的程序执行的过程相信有的小伙伴就会有一个疑问我们在从磁盘到内存的过程中我的文件系统驱动器可以从磁盘中拿到指定的文件是因为我已经把该文件给包装好了并且自己找到点击了该文件那当CPU从内存中获取该文件的时候为什么不需要经过我的操作也可以准确、完整、快速的拿到该文件呢并且当我在内存中存放了很多不同的可执行文件时我的CPU是怎么区分这些数据从而执行我想要执行的程序呢 想要解决上述两个疑问我们就需要引入进程中的一个很重要的概念了pcbpcb也叫task_struct顾名思义就是一个结构体一个任务结构体该结构体用来干嘛的呢 本质上此时的task_struct就是用来存储文件相关的属性和内容的并且此处强调文件 内容 属性这样我把我的每一个我想要执行的文件通过操作系统加载到内存之后有强迫症并且能干的内存就把这些文件一个一个的放到了相应的task_struct中加载一个文件内存就生成一个task_struct这样内存就可以通过task_struct结构体来把加载到内存中的数据按照按照task_struct结构体中存储的属性地址或者名字来对内存中各种各样的代码和数据进行一一对应管理从而解决第一个问题实现准确无误的给CPU提供数据。
具体管理方式 内存管理task_struct结构体并且此处强调管理 先描述再组织此时因为我们已经用task_struct对文件的内容和属性描述好了所以此时就只需要进行组织我们的内存就完成了管理各种各样的文件的任务了此时内存只要在每一个task_struct结构体中增加一个指针也就是以单链表的形式将这一个一个的task_struct结构体链接在一起我们的内存就完成了管理工作此时无论CPU想要获取那个数据获取那个优先级高的数据都可以说是很简单的就可以快速完整的从内存中获取。当然这个获取的过程还是由我们的操作系统来完成的。 回顾进程 基本概念程序的一个执行实例正在执行的程序等 内核观点担当分配系统资源的实体浅薄理解系统资源就是CPU资源和内存资源具体理解请看该链接系统资源深入理解 回顾pcb 基本概念当进程信息被放在一个叫做进程控制块的数据结构中可以理解为进程属性的集合相应的pcb就对应着相应的进程的信息 浅显错误理解进程 进程就是将一个可执行文件通过操作系统加载到内存之中 正确理解进程 进程是 内核数据结构 该进程对应的代码和数据
理解操作系统和进程pcb的关系
操作系统为了管理我们的进程就必须从进程当中提取或者抽象出与进程相关的属性集合构建出对应的数据结构对象再加上从外设中加载到内存中的和该进程相匹配的代码和数据所以操作系统对进程的管理并不是对内存中的对二进制文件做管理而是抽象出进程的数据结构就是pcb中的属性集合当然此时pcb是可以通过属性集合找到对应的内存中的代码和数据所以该进程创建的内核数据结构压根就不关心代码和数据在哪里只关心该进程的进程控制块也就是pcb。
所以进程控制块就是 所有加载到内存的进程通过内存创建出来的这种特定的用来描述进程的数据结构结构体对象就叫做该进程的进程控制块简称pcb。 进程状态问题
为了深入理解什么是进程此时我们就从进程的状态为切入点详细的了解一下有关进程的知识首先我们要明白一个进程是可以有好几个状态的在Linux内核里进程也叫做任务
深入进程状态
什么是进程状态呢首先从一个生活小问题出发当电脑在使用一款软件的时候例CSDN此时我们一直在CSDN上码字那么此时的CSDN是否是一直属于运行状态呢此时的一直属于运行状态指的是一直处于CPU的调度状态面对这个问题答案肯定是否定的因为在电脑中时刻存在着很多的进程例如操作系统本身的进程此时如果需要让每一个进程都可以得到运行CPU就需要对这些进程进行管理例如切换进程一个进程被CPU处理了之后又从CPU上拿下来然后让CPU处理别的进程然后该进程被重新进行管理排队之后轮到该进程时该进程才会被再处理但由于CPU的运算速度和我们的感知相差巨大所以此时我们默认这些进程是同时被CPU执行的所以默认进程是同时运行的本质上却是进程一个一个的被切换交替执行。此时就可以由切换进程这个概念引入我们之后要学习的进程状态的概念了什么是进程切换呢如何进行进程切换呢让我们带着这些问题首先来看一下什么是进程的状态。
搞定了上述的小知识此时我们就再来看一下操作系统中进程在被执行的时候涉及了两个非常重要的概念吧一个是阻塞一个是挂起没错就是高高挂起的挂起但此挂起并非彼挂起哦
阻塞
当我们写了一个程序生成了一个二进制可执行文件该文件被加载到了内存但在内存中时该二进制文件自始至终都没有被CPU执行此时该文件在干什么呢或者说此时该进程在干什么呢或者说此时该进程是属于什么状态呢通过这个场景此时我们可以想象到另一个场景就是当我们的电脑执行的程序过多的时候此时如果想要执行一个二进制文件当我们点击该文件的时候就有可能会导致电脑卡住程序不能立即执行此时该场景就相当于是上述的那个场景文件被加载到内存之后不执行所以此时该进程就是属于卡住了卡住了也就相当于我们要理解的阻塞了。那么为什么会卡住呢通过上述我们知道电脑中是有非常多的进程需要被执行的并且进程的执行是需要资源的此时的资源就好比我们上述所说进程的基本概念中的系统资源因为一个电脑中的资源是有限的所以此时进程卡住阻塞的本质就是进程因为等待某种条件就绪而导致的一种不推进的状态也就是进程卡住了。
总阻塞一定是因为在等待某种系统资源。浅显理解系统资源CPU资源、内存资源、网络资源、外设资源等
那么什么叫做等待什么叫做资源和等待资源呢 其实这个概念是非常好理解的大家在生活中肯定都有遇到过此时我们就以一个生活中的场景来抽象这些问题例下图 一个银行排队的场景当我们想要办理一张银行卡或者申请贷款之类的第一件事情就是前往银行抽象成文件被加载到内存之中第二件事情就是排队等待柜台处理抽象成在内存中等待CPU处理第三件事情就是办理业务抽象成进程被CPU处理第四此时因为你的业务属于比较复杂的业务需要你有完整的手续才可以进行抽象成一个程序想要被执行就要先拥有各种资源的使用权第五 重点由于业务安全性比较高需要你重新填保证单、个人信息之类的但是此时该保证单和个人信息表没有了需要等待银行工作人员去打印新的保证单和个人信息表所以此时柜台就会让你先去别的地方进行等待让下一个人先到柜台办理等你把保证单和个人信息表填好了之后你才可以再到柜台办理该业务抽象成CPU此时没有相应的资源需要你继续等待等到你拥有了资源之后才可以继续执行 所以当我们去别地方等待新的单子进行填写的时候就是程序阻塞的时候并且此时的状态就叫做阻塞状态。
结合上述的阻塞理解和下面的这个抽象银行理解此时我们具体把程序等待资源的过程给搞明白了但是我们还并不明白程序到底是如何进行等待 为了搞懂这个问题就要涉及到操作系统是如何管理我们的软硬件的我相信大家对这个概念是有一定的了解的操作系统通过先描述再组织的方法对各种软件和硬件进行管理具体方法把无论是硬件还是软件都给抽象成一个一个的结构体然后结构体中存在指针变量通过该指针变量对无论是软件结构体还是硬件结构体都以特殊的数据结构链表、队列、栈的形式进行增删查改。 所以进程是什么呢操作系统需不需要对其进行管理呢如果要管理应该怎么管理呢显然这些问题对于现在的我们来说答案是呼之欲出的当然要管理并且操作系统还是使用和以前一样的办法先描述再组织 通过该办法对进程进行合理的管理当然这也就是我们上述文章开头复习的内容有关pcbtask_struct 的内容操作系统就是通过pcb结构体对进程进行管理增删查改所以有了这块的知识我们就可以解决程序是如何进行等待的问题了操作系统将需要等待资源的进程以pcb结构体的方式链接到特定的数据结构中此时该数据结构中的结构体再被操作系统一个一个的调用此时操作系统调用数据结构中的pcb结构体的顺序就是进程等待的过程。
强调描述就是结构体中成员变量的类型组织就是数据结构链表、队列、栈、等
总进程等待某种资源本质就是把该进程的pcb结构体给链接到某个与外设有关的资源的数据结构队列中去排队此时CPU就不会调用它在我们看来该进程就是卡住了所以阻塞就是不被调度并且一定是因为当前进程需要等待某种资源就绪导致进程pcb结构体需要在某种操作系统管理的资源下排队(一般是外设资源下)所以pcb是可以被维护在不同的数据结构队列中的使进程可以被快速的完成用户得到稳定、快速的体验。 挂起
当我们理解了什么是阻塞现在开始学习挂起就会变得更加的轻松了什么是挂起为什么会出现挂起的概念让我们从问题出发来寻找答案首先第一步还是回到阻塞中的问题当一个程序被阻塞的时候此时就导致该进程的pcb结构体被链接到对应的资源数据结构队列之中在该数据结构队列之中排队等待相应的资源假设一个场景当电脑中有非常多的程序需要运行时把非常多的代码和数据加载到内存中由于资源有限只有少数的程序可以被CPU处理大部分程序的pcb需要等待此时就会导致内存中不仅存储了大量的pcb结构体还存储了大量的该pcb结构体对应的代码和数据按原理来说pcb结构体所占的内存空间应该是不大的因为其只是包含文件代码和数据的各种属性而已但是如果代码和数据存储在了内存之中那么此时内存就会严重不足此时就会导致很多的程序直接崩溃所以当我们的操作系统识别到这种不工作并且还占用大量的内存的程序就会把该程序的代码和数据给放到磁盘中存储而不是在内存中这样就可以很好的减轻内存的存储压力只有当对应的pcb结构体要被CPU调度的时候才会把该pcb对应的代码和数据给重新加载到内存之中所以这种把进程的代码和数据暂时性的由操作系统从内存交换到磁盘的行为我们就称之为是该进程的挂起状态。 简而言之就是进程的pcb结构体没有和该进程的代码和数据同时处于内存中该进程就处于挂起状态。
全称阻塞挂起状态。
通过文字描述之后此时我们可以很好的理解进程中的阻塞和挂起状态但是一个进程的运行并不只有这两个状态如下图为一个进程的具体状态的转换图 此时让我们通过这个图通过上述的阻塞和挂起状态与图中其它状态之间的联系让我们去了解一下别的进程状态和各个进程状态之间的切换关系。
进程的状态
一个进程在执行的过程中是有很多的状态的R - 运行状态 并不意味着进程就是在执行它表明该进程要么是在运行中要么是在运行队列里S - 睡眠状态意味着进程在等待事件的完成有时候此时的睡眠也叫可中断睡眠D - 磁盘休眠状态有时候也叫不可中断睡眠状态在这个状态的进程通常会等待IO的结束T - 停止状态可以通过发送停止信号给进程来停止进程这个被暂停的进程可以通过发送开始信号让进程继续运行X-死亡状态 这个状态只是一个返回状态你不会在任务列表里看到这个状态Z-僵死状态进程已经退出但资源没有完全被释放时处于的一种状态等待后续被处理的一种状态
了解了剩下的基本进程状态此时我们就开始一一谈谈这些状态首先是运行状态和睡眠状态R、S 如下图我们写了一个代码并且让它运行起来此时就可以通过Linux操作系统具体的看一下这个代码此时运行起来之后对应的进程是属于什么状态如下图 可以发现当我们有打印语句的时候我们的进程就算运行起来此时也不是运行状态R而是睡眠状态S并且当我们把打印语句给注释掉的时候此时的进程运行起来之后就是运行状态R了这是为什么呢原因 当我们在第一个代码中输入打印语句的时候此时表示我需要打印出我想要的语句此时就会导致该代码生成的进程具有打印属性此时该进程就需要有打印语句的资源也就是外设中的显示器所以当CPU对该进程进行执行的时候该进程就需要有外设这个资源如果没有按照原理此时该进程就会被操作系统给链接到有关外设的数据结构队列中去排队并且又因为此时的这个程序的代码是一个死循环的代码此时就需要频繁的打印导致每次CPU执行该进程该进程都需要去频繁的访问外设频繁访问外设就会导致外设资源不足所以此时就会导致该进程直接就不是在CPU的队列中排队而是在外设的队列中排队然后等待外设就绪之后再回到CPU运行队列中然后此时我们根据运行状态R 进程只有在运行中或者是在运行队列中才算是运行状态此时就可以很好的理解为什么上述的代码不在运行状态而在睡眠了因为频繁访问外设导致外设资源不足进程需要在外设队列中排队不在运行队列导致不是运行状态。 当然这也就是为什么把打印语句去掉之后该进程的状态就从睡眠状态变成了运行状态。
总只要进程不是在运行中或者CPU运行队列中而是在等待某种资源的运行队列中此时该进程就不叫运行状态。
本质CPU运行速度太快而程序中打印代码访问外设的速度跟不上CPU的速度导致被频繁的从CPU运行队列切换到外设的运行队列。当然队列都是由操作系统维护的切换工作自然也是由操作系统来完成 不可中断睡眠状态D
通过上述的例子我们把运行状态和睡眠状态可中断差不多搞清楚了这边再学习一下不可中断的睡眠状态D此时我们通过一个场景来理解不可中断睡眠状态的理解首先明白一点当我们的操作系统当中有非常多的进程时并且有的进程处于不工作状态的时候操作系统具有删除进程的功能并且由于进程长时间不工作操作系统会将该进程存放在内存中的代码和数据给转换到磁盘当中在该情况之下磁盘中的代码和数据对应的进程被删除之后会导致一个很严重的问题就是这些代码和数据无法被找到操作系统是不允许这样干的所以研发操作系统的人就设计出了一个叫不可中断睡眠状态只要此时的进程属于该状态那么它就不允许被操作系统删除这样相应的在磁盘中的数据就不会丢失任然可以被CPU执行。并且处于该状态的进程只有两种方法可以删除一是等待其自己醒来二是关机重启。所以D状态不可中断状态是一个非常不好的进程状态只要电脑中有该状态的进程那么电脑就快要崩了。
停止状态T
如下图 我们可以发现进程的状态处于停止状态T的时候在T的后面并没有加号只有当进程属于睡眠状态S时它的后面才会有一个加号那么这个加号是什么意思呢此时要理解这个加号我们就需要引入一个新的概念叫前台和后台所以此时进程状态中有带加号的就表示在前台运行不带加号的就表示在后台运行在前台运行的程序可以使用CtrlC或者kill -9pid进行终止在后台运行的程序却只可以使用kill -9pid进行终止所以我们的停止状态T都是在后台运行的。
总除了运行状态无论是可中断睡眠状态、不可中断睡眠状态还是停止状态本质上都是阻塞状态
僵尸状态Z
基础概念僵尸进程是非常特殊的一种它已经放弃了几乎所有内存空间没有任何可执行代码也不能被调度仅仅在进程列表中保留一个位置记载该进程的退出状态等信息供其他进程收集(如供父进程)除此之外僵尸进程不再占有任何内存空间。 理解僵尸进程我们还是从问题出发我们为什么要创建进程呢原因是因为我们要执行代码我们为什么要执行代码原因是因为我们需要代码为我完成某个工作所以总的来说创建进程就是需要它来帮我办事。此时假如我们很关心这个代码的结果那么此时我们就需要去了解进程的结果例我们代码中的main函数此时都会和return配套使用此时的return函数就是一个进程的退出码的意思并且在Linux中查看进程的退出码指令echo $?所以使用该指令就是获得进程退出码一个方法但此时还有另一个方法就是僵尸进程的概念当Linux退出的时候一般不会立即彻底退出而是维持一个叫僵尸状态Z的状态这样可以方便后续父进程或者操作系统去读取该子进程退出的退出结果通过僵尸进程的概念此时我就有了另一种获得退出结果的方法了。
如下图从代码角度理解僵尸进程 可以发现此时我们的子进程和父进程都是处于睡眠状态S所以按照上述的原理此时我们使用kill -9把子进程杀掉那么此时的该进程并不是处于死亡状态X而是处于僵尸状态Z如下图所示 所以此时的子进程就从睡眠状态S变成了僵尸状态Z所以根据僵尸进程的概念我们可以知道该进程此时是处于死亡状态但是并没有被清理资源没有被释放完(内存所以如果这些资源没有被释放又会有什么问题呢就会导致内存泄露问题就可能导致程序崩溃。
总所以为什么要有僵尸状态呢就是为了可以让别人去甄别该进程退出的原因和结果。所以维持僵尸进程就是为了可以让父进程或者操作系统读取到退出结果和相关信息。 总结进程状态的本质可以说是非常的枯燥的但是如果可以结合生活中的例子来抽象进程状态就会使进程状态的学习变得更加的轻松