当前位置:   article > 正文

【Linux】进程概念(3)(进程的状态 running 阻塞sleeping 、disk sleep、tracing stop 挂起 死亡dead zombie)

disk sleep


进程的状态

  • 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。

  • 进程的状态:
    运行 新建 就绪 挂起 阻塞 等待 停止 挂机 死亡 …

为什么会有这些状态?

所有的进程状态的本质就是为了满足不同的运行场景的。

1.普通的操作系统层面如何理解上面的概念?运行 阻塞 挂起

进程启动起来会被加载到内存,也就是操作系统内部,并且操作系统为了管理它,必须先描述再组织,如果进程当前想在CPU运行,CPU要在内核里为我们维护一个运行队列,比如struct runqueue 这个队列说白了就是对我们进程的运行的管理,如果想运行多个进程,但是CPU只有一个,CPU资源有限,所以运行进程要排队,即进程队列(进程排队),一般来说一个CPU一个运行队列,这个是内核设计好的。让进程在CPU运行是让进程入队列,即先进先出,所谓的入队列本质是将该进程的task_struct结构体放入运行队列中。,让进程的PCB结构体排队,它
是一个内核的数据结构对象,所以运行队列里包含了task_struct *head,指针指向第一个进程,第一个进程内部有对应的链接属性指向第二个进程,所以每个进程都有代码和数据,所以CPU要调度只要找到自己的运行队列,再用head指针找到其中某一个进程的PCB,然后执行该进程的代码。

所以让进程去排队并不是进程的代码和数据去排队,而是操作系统描述进程PCB结构体去排队。
在这里插入图片描述
CPU很快,运行一个进程只要几位秒,运行完所有进程很快,在运行队列里的进程都叫做运行状态。

进程PCB在运行队列中就是运行状态,不是这个进程真正在运行,才是运行状态。

每一个进程都有一个状态,所谓的状态就是进程内部的属性,进程的所有属性都在进程的PCB(task_struct)放着,可以把状态理解成整数int(1:run,2:stop,3:hub,4:dead…),整数是几状态就是什么。在内核可能表示为#define R 1

根据冯诺依曼,CPU很快,所有的硬件很慢但是进程或多或少都要访问硬件,硬件也很少基本上都只有一个,每一个进程在访问外设的时候,和CPU不一样,CPU很快,外设很慢,比如说进程A在访问磁盘,B、C也来了,但是得等待,硬件被多个进程访问,没有准备好的时候,进程就只能等待,不要只以为,你的进程只会等待(占用)CPU资源,你的进程可能随时随地要外设资源。
每一种硬件自己也有自己的task_struct * wait_queue,也可以维护自己的等待队列,一个CPU正在执行某个进程,发现这个进程要向磁盘写入数据,但是磁盘此时没有准备好,CPU不陪着磁盘等待,此时CPU把进程从运行队列里拿出来,链入到磁盘的等待队列里面,此时CPU继续调度运行队列的别的进程,所以CPU永远都在执行运行的进程,一旦代码有需要访问外设并且需要等的时候,此时就把进程放在对应硬件的等待队列里。 这个状态就成了 阻塞状态,即不能被调度,在等待某种资源。
改变状态即是把task_struct对象放到不同的队列中。

磁盘准备ok,可以开始运行了,磁盘准备好了,操作系统必须得知道,操作系统就把进程拿到系统里把状态改成R,并放进运行队列里,后面CPU会自动调度进程,继续访问磁盘。

所谓的进程不同的状态,本质是进程在不同队列中等待某种资源,

我们把等待外设的状态叫做阻塞状态。进程不同的状态就说明进程在不同的等待队列里。

对我们理解成本高的两个状态是挂起和阻塞。

挂起:

运行可执行程序bin.exe,要把它加载到内存里,CPU为了管理这个进程就先描述在组织即(task_struct),如果我们这个进程当前访问外设,并且此时的状态不是运行状态,是一种阻塞状态,此时它要等磁盘,如果系统存在大量的进程,每个进程都有大量的代码,假如有三个都在进程都在等磁盘,一旦阻塞了就不会被CPU调度即立即执行。更重要的是它们要等待很长时间,PCB是要占内存的,我们写的代码和程序也是要占内存的。在等待过程中,进程的代码和数据短期不会被使用,万一内存空间不够了,操作系统就帮我们处理这个情况:反正此时的进程不会被立即调度,而且进程的代码和数据不会被执行,给了进程空间但是进程短期不用,此时操作系统把进程的PCB留着,代码和数据不放在内存里了,而是把代码和数据暂时保存到磁盘上,这样就节省了一部分空间了,那么操作系统就可以使用这一部分空间去继续去运行其他程序。**这种暂时把它的代码和数据换出到磁盘的这种进程,我们叫做该进程被挂起了。**可以理解成这个进程的内核数据结构在内存中还在,但是只有一部分,证明着它的存在。操作系统的管理策略是合理的而且是对待所有进程的,当我们的进程想回去的时候,操作系统就重新把我们的代码和数据加载或把偶才能到磁盘,就是 内存数据的换入换出。

请问挂起和阻塞这两个状态有什么区别?

结合上例来看挂起一定阻塞,阻塞不一定挂起。

后面还有阻塞挂起状态、挂起阻塞状态、新建挂起、就绪挂起、运行挂起,挂起可能和其他状态各种组合。

2.Linux是怎么做的?

要谈具体的进程状态就得谈具体的操作系统。
下面就是Linxu下常见的进程状态
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

进程为R状态,下面我加点东西,
在这里插入图片描述

在这里插入图片描述
当前进程状态是S,就是sleep,但是我们发现下面的进程在疯狂的打印。为了让大家看的更直观,我们继续修改代码,
在这里插入图片描述

在这里插入图片描述

我们的printf本身是访问显示器,显示器是外设,比较慢,等显示器就绪要花的时间长,%99的时间都是在等IO就绪,即等显示器准备好,%1再执行代码,所以查的时候大部分都是S状态。

如果想看到运行状态,只能增加运行状态的概率,
在这里插入图片描述
S就是阻塞状态的一种。
T状态就是暂停状态。教材一般把T状态归结于挂起和阻塞,在Linux中是有暂停状态的,

在这里插入图片描述

此时我们发现进程状态变成R,

在这里插入图片描述

在这里插入图片描述
系统当中有很多信号,kill-l可以查询,之前我们使用过9号也就是杀掉进程。
19号信号是暂停的信号,我们使用19号信号,进程就暂停了。
kill -19 22346
在这里插入图片描述
进程就从R状态变为T(stoped)状态了。

当前进程暂停了,可以被挂起,但是它也属于阻塞的一种,因为它当前没有代码被运行了。阻塞后有没有被挂起由操作系统决定。
此时我们让他继续 kill -18 22346

在这里插入图片描述
此时我们让暂停的进程运行了。

继续修改代码
在这里插入图片描述
在这里插入图片描述

一旦运行进程,shell无法活得命令解析了,这个叫做前台进程,我们使用ctrl+c可以结束进程,我们继续试着暂停一下,
在这里插入图片描述
状态变成T状态了,我们让他继续运行,
在这里插入图片描述
我们发现状态变回S但是 + 不见了,此时我们ctrl + c发现进程关不掉了,此时进程变成了后台进程。

所以状态前面带加号的是前台进程,不带加号的是后台进程,我们用信号杀掉kill -9

D(disk sleep)状态:

这个状态叫做深度睡眠,S是浅度睡眠(可以被终止)

背景:进程A往磁盘写数据,磁盘把数据写完,告诉进程A是否成功。

磁盘很重要,保存的是未来我们用户的数据,不敢丢失,所以一个用户进程A,抱着10000条用户数据在内存里让磁盘给它写入某个区域,磁盘开始写了,写的过程中,进程A就在内存当中等待磁盘IO的结束,此时计算机操作系统内部资源变得吃紧,操作系统就开始来回检查,挂起了一大堆进程的时候还是没用,此时发现进程A还在悠闲的等的时候,直接把进程A干掉了,当磁盘把数据写了一部分出问题了想去问问进程A怎么处理,然后它去问进程A,但是发现进程A没有响应,它就把数据丢掉了,这个时候用户来了,发现数据丢了,为了避免以后这种情况的发生,用户给进程A发了个免死金牌,操作系统可以杀别的进程,但是不能杀带有免死金牌的进程,此时就引入了一种新的状态叫做D状态,深度睡眠,在该状态下的进程无法被操作系统杀掉(OS),只能通过断电或者进程自己醒来来解决!想看到D状态,必须得在高IO的情况下,用户无法设置,操作系统也不行。
dd命令是把临时文件的数据在磁盘上做IO,一瞬间可能IO上几十个G。
在这里插入图片描述

t(tracing stop):

它也是一种暂停状态,gdb在调试程序的时候,gdb进程处于S状态等待输入,但是我们发现我们自己的进程所处状态是t这种t状态也是一种暂停状态,tracing stop表示该进程正在被追踪。
在这里插入图片描述

在这里插入图片描述

所以我们就理解一个进程为什么能被调试,断点处停下来就是进程停下来了,停下来之后等待继续运行。

X死亡状态(dead):

这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

Z (zombie) 僵尸进程

在Linux中还有一个非常重要的状态 Z (zombie),僵尸状态是一种非常特殊的存在。

当一个进程被创建出来的时候,是需要它为我们帮忙办事完成任务,那么就存在进程给我们把事情办得怎么样?我们需要知道进程完成的怎么样。
所以进程退出的时候,不能立即释放该进程对应的资源,保存一段时间,让父进程或者OS来进行读取。

僵尸状态是一进程状态的正常的一种,它已经退出了,当前的资源没有全部释放,还有一部分资源一定要保存起来,这部分资源要保存起来,供上层读取得知进程是因为什么原因退出的。

我们要查看僵尸进程很简单,只要保证进程推出了,但是没有被回收,一般进程回收是父进程或者OS来操作。我们创建一个子进程,让父进程不要退出,父进程什么都不做,让我们的子进程正常退出。此时子进程就处于僵尸状态。

在这里插入图片描述

在这里插入图片描述
我们在进程控制去学习解决这类问题。

僵尸进程危害:

僵尸进程退出的时候信息会写到PCB里的,PCB并没有释放,假如父进程没有释放,那么子进程永远无法被回收意味着系统内可用的资源越来越少,这个问题就叫做内存泄漏。

孤儿进程

父进程先退出,子进程就称之为“孤儿进程”
在这里插入图片描述
此时父子进程一直在运行,现在我们杀掉父进程
在这里插入图片描述

父进程被杀掉了,为什么我们没有见到父进程的僵尸状态,引进就是父进程也有父进程。
在这里插入图片描述
我们发现父进程变成了1,1号进程就是我们的操作系统,在这里插入图片描述
换言之对我们来讲,子进程和父进程同时运行,但是父进程先退出了,子进程被操作系统即1号进程所领养,这样的进程叫做孤儿进程。

小结

  • 1.父进程先退出这种现象一定存在的。
  • 2.子进程会被操作系统领养----1号进程。
  • 3.如果不领养,那么子进程退出的时候,对应的僵尸,便没有人能回收了。
  • 4.被领养的进程叫做孤儿进程。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/535414
推荐阅读
相关标签
  

闽ICP备14008679号