进程管理3——进程状态

目录

一 Linux操作系统进程状态

二 大体分类

新建状态

运行状态

阻塞状态

挂起状态

三 Linux内核中进程的其中状态

1 R 运行态——调度CPU资源(运行状态)

2 S D 睡眠状态——等待资源就绪(阻塞状态)

3 T t 暂停状态——停住代码

4 X Z 终止状态


一 Linux操作系统进程状态

在OS中存在大量的task_struct结构体。用来维护一个一个的进程。task_struct中一般保存该进程的属性值,其中有一个属性值叫做status,是int类型的。操作系统会将各种状态定义成宏:比如#define NEW 1……

那么task_struct的status维护对应的int值,就变成了维护对应的状态。

二 大体分类

一般简单地划分成:新建状态,阻塞状态,运行状态,挂起状态四个状态。

新建状态

刚被创建,暂时不能被运行。其实一个进程创建出来就是为了被调度,这个状态是理论层面上为了自圆其说存在的一个状态,和实际操作上又有所不同。

运行状态

之前提到过,CPU会通过调度算法来执行相应的运行队列。那么task_struct结构体在运行队列中排队,就叫做运行态。这时候可以是正在被执行,也可以是在运行队列中等待被执行。

阻塞状态

系统中存在各种资源,网卡,磁盘,显卡等其他设备,多个进程访问除了CPU以外的设备的队列,叫做阻塞队列。

比如我今天写的一段程序,他需要先编译链接运行变成一个进程,被CPU调度。CPU在调度这个进程的时候,发现里面有scanf的语句,需要从键盘上读取数据。CPU就把他放到了等待磁盘资源的这个队列中去,(有可能有多个文件同时需要访问磁盘,向磁盘中写数据,因此即使是磁盘也会有队列)等完成了磁盘资源的等待之后,才放回CPU重新执行。

挂起状态

内核或者操作系统需要维护的一种状态。磁盘上存在很多个分区,其中有一个叫做SWQP分区。内存里面有很多进程(代码+数据+对应的PCB结构体)存储着,他们需要被执行。当进程数量太多了,内存资源快不足了的时候,操作系统就会将长时间不执行的进程的代码和数据换出到SWAP的磁盘中,只保留task_struct结构体。因为一个进程实际上占空间最多的是他的代码和数据。在需要运行这个进程的时候,就将对应的代码和数据从SWAP分区中放回内存的运行队列中,等待调度器来进行调度。

在上述的过程中,内存中只有对应进程的task_struct的进程状态,叫做挂起状态。

 SWAP分区一般不会满,因为OS不会无脑换入换出,换入换出的过程实际上是IO的过程,会影响效率。

三 Linux内核中进程的其中状态

一般在linux内核中,进程存在七种状态。R S D T t X Z这几种。他们保存在一个指针数组中。

static const char* const task_state_array[] = {
	"R(running)",//0 运行状态
	"S(sleep)",//1 可中断睡眠状态
	"D(disk sleep)"//2 不可中断睡眠状态
	"T(stopped)",//4 停止状态
	"t(tracing stop)",//8 针对于调试的停止状态
	"X(dead)",//16 死亡状态
	"Z(zombile)",//32 僵尸状态
};

关于前台进程和后台进程:

 + 代表这个任务属于前台进程,可以被结束。前台任务启动,执行命令没有效果。不带+的叫做后台进程或者常驻进程,他在执行的时候,不能被终止,并且命令还能执行。

关于信号:由于后续演示进程状态的时候需要用到,因此简单引入。

kill -9 管理员信号 杀死这个进程

kill -19 暂停这个进程

kill -18 继续这个进程

前台进程和后台进程(&)不影响命令行操作

1 R 运行态——调度CPU资源(运行状态)

根据我们自己的理解,执行一个有循环语句的程序的话,查看这个进程的状态,他应该是处于R状态。但是实际上,当我们带上printf的时候,是S状态;不带的时候才是R状态。

 

 

为什么会这样呢?

CPU运行速度非常快,而printf调用键盘资源的运行速度与CPU的运行速度相比就慢了很多。在程序执行的时候,把阻塞队列中等待资源的数据放到被CPU调度的运行速度中(printf的过程),由于阻塞队列所占的时间很长,运行队列所占的时间非常短,我们观察进程状态的时候,也很难观察到对应的R状态。

2 S D 睡眠状态——等待资源就绪(阻塞状态)

①S 可中断睡眠(也可能是挂起状态)

上述演示的过程中也出现了对应的S状态。这种睡眠状态是因为在等待资源就绪。S是可以被打断的意思——也就是说,你可以杀死这个等待资源就绪的进程。

②D 磁盘睡眠 也叫不可中断睡眠 

为什么会有这样的一种睡眠状态呢? 

有这样的一个场景:

执行某文件的读写,进程A要访问磁盘中的某个位置,将数据刷新到磁盘中。(数据量非常大)

磁盘去执行读写的任务了。这之后成功或者失败读写数据的结果,都会反馈给CPU,此时该进程是阻塞状态。

当服务器压力过大的时候,OS会通过一定的手段,杀掉一些进程,起到节省空间的作用。OS如果此时内存状态非常紧张,服务器压力过大,看到进程A在休眠,干掉了进程A(换言之,也就是该睡眠可以被中断) 。

那么此时数据如果读写失败了,怎么报告?向谁报告?CPU中的进程都被杀掉了。磁盘就会把对应的数据扔掉。造成数据丢失。

导致磁盘读写数据丢失最本质的问题:进程A被杀掉了。

因此会有一个相关的睡眠状态,叫做D状态。不可被中断,叫做深度睡眠,也就是不可被杀掉的睡眠。

只能当最后取得了对应的读写结果,才会醒来。除此之外,只有关机重启才能切换。

即使是管理员信号 kill -9也不可以杀死该进程。

3 T t 暂停状态——停住代码

暂停和休眠的区别:休眠在系统层面上是阻塞状态,等待某种资源。

T本身没有等待任何资源,只是把对应的代码停住了。

①T 

上述过程中已经演示了T状态。本身该程序本来在运行,结果发送了19号信号,让该进程暂停了,就出现了对应的T状态。

②t 

也是暂停状态,只不过是在调试的过程中出现的一种状态。

用gdb调试的时候,打上断点再来观察进程的状态就能观察到了

4 X Z 终止状态

①X状态 (dead),终止状态,他是因为进程已经挂掉了,并且可以被操作系统回收了但是有时候,OS很忙,可能没来得及及时回收这个进程,于是就会出现这样的一个状态。但是她的瞬时性很强,很难模拟。

②Z状态(僵尸状态)

是什么?父进程还在运行,但是子进程已经退掉,并且没有把对应的信息反馈给父进程,那么此时子进程就不能被OS回收,这个状态叫做僵尸状态。

为什么会存在这样的状态?父进程或者OS关心这个子进程的状态。因为父进程创建子进程,是需要子进程帮忙实现自己的一部分任务,那么要知道任务完成的怎么样了。因此父进程主动检测子进程状态。维持该状态,为了让父进程和OS进行回收。

一般是由父进程回收的,如果是出现了僵尸进程这种状态之后,父进程也挂了,就要由OS回收。

模拟:

 

 

 

 

危害:

一个进程退出:PCB保留,将代码和数据释放掉。

系统中如果恶意程序:创建子进程,处于僵尸状态,不释放,父进程不回收。那么会一直占用资源(CPU)导致内存泄漏。维护退出状态本身是需要数据维护的。

拓展:孤儿进程

创建子进程,子进程还没退出,父进程先挂掉了。这叫孤儿进程

一般回收子进程,都是由父进程回收的。创建子进程,子进程还没退出,父进程先退出了。那么此时谁回收子进程的资源呢?此时该子进程必须被领养,是由1号进程(Init,OS)领养。

但是如果操作系统子进程过多的话,也是需要一步步回收的。父进程为1号进程的Z状态进程很难观察到。因为速度很快。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值