Linux进程状态

前言

上一期我们对进程的概念做了介绍并尝试理解了进程。介绍了PCB属性的pid等,这一期我们来介绍进程的状态!

本期内容介绍

Linux的进程状态

僵尸进程和孤儿进程

理解进程的运行、阻塞和挂起状态

简单理解进程切换

Linux的进程状态

为了理解正在运行的进程是什么意思,我们需要搞清楚进程的不同状态!我们上一期介绍过进程的状态是进程PCB中的一个属性,也就是一个变量!例如:int status;即不同的进程状态就是内部的status的值不同而已!Linux的进程状态有7种,下面我来介绍一下!

R(running):运行状态

S(sleeping):可中断休眠状态

D(disk sleep):不可中断休眠状态

T(stopped):让进程暂停等待被唤醒(暂停状态)

t(tracing stop):让进程暂停等待被唤醒(追踪暂停状态)

X(dead):进程死亡/终止状态

Z(zombie):僵尸进程状态

上面的几种状态中除了绿色大的两种外其他都可以演示!D状态不可中断睡眠和X终止状态无验证!前者和磁盘I/O有关,后者几乎无法看到!所以,下面这两种状态就不在验证了,会直接说结论,其他的会验证~!

R状态

R(running)运行状态。运行状态并不意味着进程一定在运行中,而是他要么在运行中,要么在运行队列里。

OK,验证一下:

我们这个代码就是很简的一个死循环,根据运行状态的介绍,当着个进程运行起来时后他就是R状态!OK,是不是呢?我们来看看:
还是以前的监控脚本:

while :; do ps ajx | head -1 && ps ajx | grep status | grep -v grep; sleep 1; done

这怎么和我们的介绍不一样?不应该是R状态吗?怎么是S?OK,我们把执行的语句注释掉再看看:

这样就变成了R了,这也就说明了刚刚引起R变为S的原因就是这两条语句!OK,我们下面的S状态解释!

S状态

S(sleeping)可中断休眠状态。进程等待“资源”的就绪/事件的完成

等待资源的就绪其实上面的例子已经可以说明了!上面的这代码一开始没有注释时在一直想显示器写" I am a process!"本来应该是R状态的但是是S状态,其实这是合理的!因为CPU执行printf的那一句是非常非常快的!根据上上期的冯诺依曼体系结构可以知道:CPU执行完的结果是写在内存的,然后再由内存在刷新到外设的!由于CPU执行的很快,内存向外设刷时需要等待显示器资源的就绪,而显示器资源相较于CPU很慢所以上述进程就是S状态!

D状态

D(disk sleep):不可中断休眠状态/磁盘睡眠。通常是等待磁盘I/O

操作系统中有很多的进程,这些进程都是要占内存空间的,而如果进程很多导致内存严重不足时操作系统有权利杀掉一些进程来释放空间!此时,如果一个进程正在向磁盘中写入1GB的数据了,由分诺依曼可知磁盘是外设,CPU的速度是很快的,当在往磁盘写入时当前的进程就进入了S状态,此时内存不足了,操作系统一看这有个休眠的把他杀掉释放一点空间吧!此时这个进程被干掉了,而过了一会,磁盘写入后的反馈结果刚给进程时,找不到进程了,而此时还有很多同类的进程在等待,所以此时磁盘就不在管找不到上一个进程的事情了,又去忙着服务其他进进程了,这就导致了那1GB的数据丢失了!假设这是1GB的银行转账记录呢???这损失可就大了!所以,为了防止这种状态的发生,与磁盘进行I/O的进程会设置为D状态,表示不可中断睡眠状态!

T状态

T(stopped):让进程暂停等待被唤醒(暂停状态)

T 状态通常是用户向进程发送信号(SIGSTOP等)让进程进入暂停状态的,需要被唤醒才可以继续执行!

这里的信号如果是第一次听可能有点陌生,但是我们以前是用过的(kill -9就是)!OK,我们来看看Linux中的信号有哪些?(可以通过:kill -l查看

我们以前用过的9号信号就是杀死进程的信号!OK,这里看到信号不知道你有没有觉得他和我们以前在C语言学的某一个东西很像?没错,就是宏!所以这里你可以给进程发字符,但也一般都发对应的数字~!OK,这里如何通过发信号让进程暂停呢?我们可以通过给进程发送19号信号(SIGSTOP)来让进程暂停:kill -19 进程pid

OK,我们现在不想让这个进程暂停了,想让他继续跑起来如何做呢?还是给他发信号:上面的19信号是SGISTOP即暂停,而18号信号是SGICONT即进程继续的信号!我们可以通过 kill -18 进程pid让当前暂停的进程继续跑起来:

OK,关于信号我们后面会在来专门谈的这里知道如何启动和暂停进程就好了!

t状态

t(tracing stop):让进程暂停等待被唤醒(追踪暂停状态)

通常是由调试器或追踪器等工具导致进程暂停的,此时进程等待被调试器继续执行等操作!

这个状态不管是VS还是在Linux下我们可是遇到过的。当我们在某一行打一个断点时,他会在运行到这一行时停在断点处,此时进程的状态就是t状态。OK,我们来看看:

我们可以看到当前的进程在第8行设置了断点后就进入了t状态,而gdb status那是gdb的进程!如果我能继续执行就会变成S/R状态(这里的代码就是上面演示R状态的那个代码是一直printf所以是S状态);

X状态

X(dead):进程死亡/终止状态

我们要知道的一点是:子进程是帮父进程执行某项任务的,最后得给父进程一个反馈的!所以,进程在退出/结束的时候会把自己的退出信息存储在自己的PCB(task_struct)中,等待父进程来读取,如果父进程读取了,此时就会释放掉当前子进程的资源!即子进程就是X状态了,但由于释放是瞬时的所以是极其难查到的!当前这个就介绍到这里,具体父进程如何查看子进程的退出信息,我们在后面的进程控制在介绍!

Z状态

Z(zombie):僵尸进程状态

这里和下面另一个孤儿一起对比介绍!(具体请看下面)

僵尸进程和孤儿进程

僵尸进程

子进程退出后父进程没有对他的退出信息做处理,此时进程的状态就是僵尸状态。此时的子进程就是僵尸进程!

我们上面刚介绍了:所有进程在退出的时候都要将自己的退出信息保存在自己的PCB(task_struct)中,等待父进程的读取,如果读取了就是X状态了,但是如果没有读取会一直存在就是Z状态,即僵尸状态了!OK,演示一下:

这个代码是让子进程跑5次然后结束掉,而父进程是一直执行的,并没有对子进程做处理,此时就是僵尸:

僵尸进程的危害

这里没有读取子进程的PCB,而进程= PCB + 它的代码和数据,子进程结束后它的代码和数据可能释放了,但是它的PCB会一直存在(因为子进程要告诉父进程你给我的任务,我做的咋样了),这样会有一个问题就是,PCB是不是也是一个个的结构体对象啊!他也是要占内存空间的,但是没有父进程读取它的PCB会一直存在,即会一直占着这块内存不释放,这就会导致内存泄漏内存资源浪费(父进程创建多个子进程不读取子进程的PCB)的问题!

这里你可能会想我们以前启动的所有进程可都没有考虑过僵尸进程和内存泄漏呀?原因是我们以前在命令行启动的所有进程它们的父进程是bash,bash会自动回收子进程的!

孤儿进程

孤儿进程是,父进进程先于子进程而结束。此时的子进程就是孤儿进程!

OK,演示一下:

让父进程跑5秒后退出而子进程一直跑,此时的子进程就是孤儿进程!

此时,要想终止孤儿进程,是无法用ctrl+C终止的!而是应该使用kill向该孤儿进程发9号信号使其结束,原因是ctrl+c是父进程给子进程发9号信号使其终止,但是这里根本就没有父进程了,就无法发9号信号了!只能通过kill -9 pid来使其结束掉!

这里现在的问题是,我们上面介绍了僵尸进程,当子进程结束时需要父进程来读取他的PCB使其结束掉,如果没有父进程读取当前子进程就会变成僵尸状态。这里父进程都先退了,那不等子进程退出的时候铁铁的变成僵尸进程??是的!这个问题操作系统也想到了,当孤儿进程退出时由1号进程(这里理解成系统即可)领养,读取他的PCB使其结束释放掉!避免其变成僵尸进程!所以这就是上面的ppid是1的原因

理解进程的运行、阻塞和挂起状态

进程的几种常见的状态

一个进程被创建后会经历不同的状态,通常被称为进程的生命周期!我们先来介绍一下操作系统的几个状态:

  1. 新建状态(New):当一个进程被创建时,它处于新建状态。在这种状态下,操作系统为进程分配必要的资源,初始化进程控制块(PCB)等。但进程还不能被CPU调度执行。

  2. 就绪状态(Ready):新建进程完成初始化后,进入就绪状态。在就绪状态下,进程已经准备好运行,只等待CPU的分配和调度。多个就绪状态的进程会在CPU的就绪队列排队等待被调度!

  3. 运行状态(Running):当进程获得CPU时间片,开始执行指令时,它进入运行状态。在运行状态下,进程正在使用CPU执行自己的任务。

  4. 阻塞状态(Blocked):如果进程需要等待某些事件的完成(如I/O操作、信号等),则进程可能会进入阻塞状态。在阻塞状态下,进程暂时停止运行,等待事件完成后才能继续执行。

  5. 终止状态(Terminated):当进程执行完毕或被终止时,会进入终止状态。在这种状态下,进程的资源被释放,PCB被销毁,但仍需要等待操作系统回收进程所使用的资源。

  6. 挂起状态(Suspended)通常指进程在执行过程中被临时中断或挂起,暂时停止执行挂起到磁盘。挂起状态通常分为两种:

    1. 就绪挂起(Ready Suspended):进程处于就绪状态时,如果被挂起,说明该进程虽然已经准备好运行,但由于某些原因(如等待某些资源)暂时无法执行。在这种情况下,进程需要等待条件满足后恢复执行。

    2. 阻塞挂起(Blocked Suspended):进程处于阻塞状态时,如果被挂起,表示进程正在等待某些事件发生,而且暂时无法继续执行。在进程进入挂起状态后,将暂停等待事件发生,一旦事件完成即可恢复执行。

这里我们主要要理解的是:运行状态、阻塞状态、挂起状态。下面我就来理解一下站三种状态!

理解运行状态

运行状态就是CPU调度CPU运行队列中的进程!(Linux中的R状态)

我们想一个进程会不会一直被调度也是就是某进程抢到CPU了会不会是一直执行完该进程才执行下一个进程呢?答案是:不会!因为CPU是基于时间片进程轮转调度的(为了公平)也就是一个进程会运行他抢到的时间片的时间,到时间了,他会被CPU上剥离下来继续到运行队列中排队,等待再次被调度!

操作系统会把在CPU运行队列中的进程(未被调度的)称为就绪状态,而被调度的叫做运行状态。结合上面Linux的状态,操作系统的运行状态+就绪状态就是Linux的R状态,因为在上面介绍了,R状态是,要么正在被CPU执行要么在运行队列里!

上面这是最简单的进程调度的方式,也是操作系统学科中通常介绍的。但是Linux并不是这样调度的!具体Linux是如何调度的我们后面再谈!

并发和并行

上面介绍了CPU是基于时间片轮转调度的,这样会保证各个进程都可以被调度,而不至于某些进程占CPU时间很长!像这种让多个进程以切换的方式进行调度,一个时间段内得以同时推进的调度方式叫做并发假设现在两个CPU,一个在调度A进程,一个在调度B进程。像这种任何时刻都有多个进程真正的同时被调度的方式叫做并行

理解阻塞状态

阻塞状态就是当前进程等待某种资源而导致暂停的状态, 需要资源满足后才可继续运行。例如:等待I/O(Linux中的S和D状态)

光说阻塞态我们难免会有一些生疏,但是我们100%是遇到过的,而且是经常遇到!比如,你在写C语言代码的时候scanf从键盘读取的时候,如果你不输入你的代码是不是一直暂停着?其实这就是当前的进程进入了阻塞状态!

OK,这就是一个阻塞态到运行态的过程!下面我就接着用这个栗子,来再谈一谈阻塞态!我们知道所有的调度都是CPU到运行队列中调度排队进程的PCB的。

现在的问题是,如果当前进程需要某些资源而不能继续执行时即进入了阻塞状态后,其PCB从CPU的运行队列中被拿下来后,会在哪里?其实当前被阻塞进程的PCB会被拿到相关资源/设备的运行/就绪队列里面等待资源,直到等待/所需的资源满足了,才会被拿到CPU的就绪队列中继续等待被调度(即被唤醒)!

也即是如下图:

总结:

1、阻塞和运行状态的变化,往往是伴随着PCB在不同的队列中,而不是其进程的代码和数据在队列中!

2、不只是CPU有等待或就绪队列,各种设备都有等待或就绪队列!

3、和我们上面介绍的Linux的几种状态联系起来,阻塞状态就是S/D状态,在等待某种资源/设备的就绪!

理解挂起状态

挂起状态是当操作系统需要释放资源或等待特定的事件发生,而将一些进程暂时唤出内存到磁盘的一种管理资源的机制或手段,这样可以更加合理或高效的使用资源!再次运行时将进程唤入到内存即可(也就是将挂起的进程PCB+代码和数据重新加载到内存即可)例如:当操作系统的内存特别吃紧的时候会将某些进程例如阻塞/休眠的进程换出到磁盘来释放系统资源给其他进程, 如果要运行这个挂起的进程了,只需要将他重新加载到内存让他的PCB去运行队列排队即可!

注意:

1、这里的将进程唤出到磁盘是将进程的PCB+代码和数据(即整个进程)唤出到磁盘!

2、这里的唤出到磁盘不是磁盘的随便一个位置,而是唤出到一个叫swap的特定空间中!

3、这其实就是一种典型的用效率换空间的方式!

简单理解进程切换

上面在介绍理解进程运行状态时,说过CPU是基于时间片而轮转调度的,也就是如果某个进程正在执行但是它的时间片用完了,他会被强制的拿下来去到等待队列中排队!此时问题就来了:被强制拿下来的进程再次执行时是从头开始执行吗??答案显然不是!那他如何知道他上次执行到哪里呢???答案是:进程在切换时会保存它的上下文(CPU内部所有寄存器的临时数据叫上下文)数据(方便再次恢复调度)

我们知道CPU附件是有很多寄存器的,例如:eac、esp、ebp等,我们进程再被CPU执行时其PCB的数据会被首先加载到各种寄存器,然后CPU读取寄存器的数据来执行相关操作!但是如果这个进程执行到一半时如果时间片完了,它此时进程要被拿下来时,它的这些寄存器的数据是不是要保存起来?原因是寄存器只有一套且它是临时的保存数据的,但是进程有很多个,每个进程都要访问这些寄存器(如果不拿走下次调度就找不到上次调度是寄存器的数据了),所以当这个进程要被拿下来时就要把这些寄存器的数据让当前进程带走,等下次被调度时,查看其上下文数据(寄存器的数据)即可继续执行!

总结

进程切换最重要的一件事情是:上下文数据的保护和恢复!

CPU内的寄存器只有一套,但是CPU寄存器的数据有多套!

寄存器不等于寄存器的内容!

OK,好兄弟,本期分享就到这里,我们下期再见!

结束语:你是春风,不应该畏惧山,而应该跨越山!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

定子的检查和包扎及转子的检查

线圈接好后 用摇表测试 线圈和外壳之间的绝缘性! 测试通过后进行焊接!,焊接的工具在后面的文章中会介绍! 焊接好后,包绝缘管。 焊接完成后 进行星型连接,或者三角形连接! 白扎带进行绑扎&…

Django初步了解

目录 一、什么是Django 二、Django的设计模式 三、涉及的英文缩写及其含义 四、安装(官方教程) 一、什么是Django Django是一个Python Web框架,可以快速开发网站,提供一站式的解决方案,包括缓存、数据库ORM、后台…

Qt模型视图代理之QTableView应用的简单介绍

往期回顾 Qt绘图与图形视图之绘制带三角形箭头的窗口的简单介绍-CSDN博客 Qt绘图与图形视图之Graphics View坐标系的简单介绍-CSDN博客 Qt模型视图代理之MVD(模型-视图-代理)概念的简单介绍-CSDN博客 Qt模型视图代理之QTableView应用的简单介绍 一、最终效果 二、设计思路 这里…

《从Paxos到Zookeeper》——第四、七章:基本概念及原理

目录 第四章 Zookeeper与Paxos 4.1 Zk是什么 4.1.1 Zk特性 4.1.2 Zk基本概念 4.1.2.1 集群角色(Follower, Leader, Observer) 4.1.2.2 数据模型 4.1.2.3 ZNode(数据节点) 4.1.2.4 Session(会话) 4.1.2.5 ACL(Access Control Lists) 4.1.2.6 Watcher(事件…

Git系列:如何为不同的Git仓库设置不同的配置项?

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【云原生】Docker 的网络通信

Docker 的网络通信 1.Docker 容器网络通信的基本原理1.1 查看 Docker 容器网络1.2 宿主机与 Docker 容器建立网络通信的过程 2.使用命令查看 Docker 的网络配置信息3.Docker 的 4 种网络通信模式3.1 bridge 模式3.2 host 模式3.3 container 模式3.4 none 模式 4.容器间的通信4.…

RabbitMQ之生产批量发送

为什么要用生产批量发送? 批量发送消息,可以提高MQ发送性能。但是 RabbitMQ 并没有提供了批量发送消息的 API 接口,使用 spring-amqp 的 BatchingRabbitTemplate 实现批量能力。 SimpleBatchingStrategy 发送策略满足以下规则会进行发送: ba…

开源模型应用落地-LangChain高阶-Tools工具-集成agents(四)

一、前言 LangChain 的 tools 是一系列关键组件,它们提供了与外部世界进行交互的能力。通过适当的使用这些组件,可以简单实现如执行网络搜索以获取最新信息、调用特定的 API 来获取数据或执行特定的操作、与数据库进行交互以获取存储的信息等需求。 本章…

图像处理的一些操作(1)

图像处理 1.安装PIL,skimage库1.1导入skimage库中的oi模块和data模块 2.读取图像文件2.1读取图像文件2.2 以灰度模式读取图像2.3 查看示例图像的目录路径2.4 读取chelsea图片2.5 加载示例图片并保存2.6 获得加载图片的信息2.6.1 输出图片类型2.6.2 输出图片尺寸2.6.…

idea生成双击可执行jar包

我这里是一个生成xmind,解析sql的一个main方法,可以通过配置文件来修改有哪些类会执行 我们经常会写一个处理文件的main方法,使用时再去寻找,入入会比较麻烦,这里就可以把我们写过的main方法打成jar包,放到指定的目录来处理文件并生成想要的结果 1.写出我们自己的main方法,本地…

Reactor模型详解

目录 1.概述 2.Single Reactor 3.muduo库的Multiple Reactors模型如下 1.概述 维基百科对Reactor模型的解释 The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs.…

《ElementUI 基础知识》el-tabs header 监听鼠标中键滚动时左右滑动(ElementPlus同样适用)

前言 收到需求,可监听 el-tabs 头在鼠标 hover 时。滑动鼠标中键,可左右滑动! 效果 鼠标中键上下滑动时;向上滑,向左移动;向下滑,向右移动; 实现 代码56 - 60行,添加…

服务器IP选择

可以去https://ip.ping0.cc/查看IP的具体情况 1.IP位置--如果是国内用,国外服务器的话建议选择日本,香港这些比较好,因为它们离这里近,一般延时低(在没有绕一圈的情况下)。 不过GPT的话屏蔽了香港IP 2. 企…

【数学建模】矩阵微分方程

一、说明 我相信你们中的许多人都熟悉微分方程,或者至少知道它们。微分方程是数学中最重要的概念之一,也许最著名的微分方程是布莱克-斯科尔斯方程,它控制着任何股票价格。 ​​ 股票价格的布莱克-斯科尔斯模型 微分方程可以由数学中的许多…

【Python项目】基于DJANGO的【医院体检预约系统】

技术简介:使用Python技术、DJANGO框架、MYSQL数据库等实现。 系统简介:系统采用了在线预约和挂号的方式,用户可以通过网站进行预约和挂号操作。同时,系统还提供了医生的详细介绍和评价,方便用户选择医生。 研究背景&a…

Linux系统编程--信号与管道

1、信号与管道是什么? 首先了解信号与管道的意义,我们需要了解Linux系统中进程之间是如何通信的。Linux操作系统下,以进程为单位来分配或者管理资源,进程之间不能直接访问资源,因此,要求进程间的资源和信息…

word中取消分页符或分段符前后的空格

在Word中,有时候,我们添加分页符后,从分页符后面的文字就全部掉到了下一页,那么如何避免呢? 选择word选项--高级,然后下滑到下面,将“取消分页符或分段符前后的空格”选中,如下图所…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

C 408—《数据结构》图、查找、排序专题考点(含解析)

目录 Δ前言 六、图 6.1 图的基本概念 6.2 图的存储及基本操作 6.3 图的遍历 6.4 图的应用 七、查找 7.2 顺序查找和折半查找 7.3 树型查找 7.4 B树和B树 7.5 散列表 八、排序 8.2 插入排序 8.3 交换排序 8.4 选择排序 8.5 归并排序和基数排序 8.6 各种内部排序算法的比较及…

Meta Llama 3 使用 Hugging Face 和 PyTorch 优化 CPU 推理

原文地址:meta-llama-3-optimized-cpu-inference-with-hugging-face-and-pytorch 了解在 CPU 上部署 Meta* Llama 3 时如何减少模型延迟 2024 年 4 月 19 日 万众期待的 Meta 第三代 Llama 发布了,我想确保你知道如何以最佳方式部署这个最先进的&…