进程的状态

这篇我们继续讲解进程相关的内容。
在这里插入图片描述

1. 进程状态

进程的状态也在task_struct里,它其实就是一个整数,用不同整数来代表各个状态
我们先讲解4个状态:

1.1 运行态

运行态在这里插入图片描述
这个我们上一篇文章说过,tack_struct会现在运行队列中等待,然后CPU会调度某个进程。那么运行态是进程正在CPU上运行,还是进程只要在运行队列中叫做运行态呢?
答案是:只要在运行队列中就叫做运行态,代表我已经准备好了,随时可以调度。

1.2 终止状态

终止状态
终止状态是进程已经被释放,叫做终止状态?还是该进程还在,只不过不运行了,随时等待被释放?
答案是:该进程还在,只不过不运行了,随时等待被释放。
那么为什么进程都终止了,不立刻释放对应的资源,而是要维护一个终止态呢?原因就是:释放是需要花费时间的,但此时你的操作系统很忙,没有时间去释放你的资源,所以会有一个终止态。

1.3 阻塞态

阻塞态
要说阻塞态,我们先补充一些知识点:
我们知道一个进程,使用资源的时候,不仅仅是在申请CPU资源。进程可能申请更多的其它资源,比如:网卡,显卡,磁盘,显示器,声卡等资源。
如果我们申请CPU资源,暂时无法得到满足,是需要排队的(运行队列),但CPU运行速度很快,我们感受不到。那么我们申请其它慢设备资源也是一样的,也是需要排队的。
在前面我们说过,操作系统进行"管理"是要先描述,再组织。所以像CPU,网卡,磁盘等也会有相应的结构体来描述。
在这里插入图片描述
假如现在有一些进程需要CPU调度,假设现在需要从磁盘中读取1G数据,但此时磁盘比较繁忙,该怎么办呢?进程还在CPU中等待吗?肯定不是。
在这里插入图片描述
它会把进程放到磁盘队列中等待,然后让CPU去调度其它的进程。

结论:当进程访问某些资源(磁盘,网卡),该资源如何暂时没有准备好,或者正在给其它进程提供服务。此时,当前进程要从runqueue中移除,然后将进程放入对应设备的描述结构体中的等待队列。

此时进程在等待的时候,该进程的代码,不会被执行了。这就被叫做进程阻塞而我们用户看到的情况是如果我们平时进程开的比较多的时候,某些进程就会卡住,此时的状态就是进程阻塞。

然后当磁盘已经准备就绪时,进程就会再被放回runqueue中,然后等待CPU的调度,完成磁盘的工作。
在这里插入图片描述
阻塞态定义:进程等待某种资源(非CPU),资源没有就绪的时候,进程需要在该资源的等待队列中进行排队,此时进程的代码并没有运行,进程所处的状态就叫做阻塞。

1.4 挂起态

挂起态
在这里插入图片描述
上图是我们的内存和磁盘,然后内存里面有许多进程被管理起来。其实我们知道内存是有大小的,并不是特别大,操作系统也会加载到内存,然后在不断加载其它进程。但此时内存不足了怎么办?我们知道操作系统是管理软硬件资源的,所以操作系统此时就会帮我们辗转腾挪。就是短期内不会被调度的进程,它的PCB虽然在其它设备的等待队列排队中,但它的代码和数据依旧在内存中,所以会白白浪费内存的空间。那么此时操作系统就会把该进程的代码和数据置换到磁盘上
在这里插入图片描述
此时的状态被称为进程挂起。这四个状态我们理解清楚了,剩下的状态我们也能进行组合理解。

2. Linux下的进程状态

我们看一下Linux内核里面是代码:

static const char * const task_state_array[] = { 
"R (running)", /* 0 */ 
"S (sleeping)", /* 1 */ 
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

我们看到这些状态和上面说的操作系统四大状态,你会发现你还是不太懂,现在我们说一下Linux下的状态。

2.1 R和S状态

我们先把准备工作做好:
在这里插入图片描述
然后我们运行:
在这里插入图片描述
从上面我们看到进程在不断运行,但是它的状态是S。其实CPU的运行速度很快,一句printf打印的很快就打印完了,大部分时间都花在了sleep函数上。我们把sleep函数屏蔽一下再看看:
在这里插入图片描述
在这里插入图片描述
我们看到进程的状态还是S,这是为什么呢?
我们知道显示器(硬件)它的速度是非常慢的,所以大部分时间其实是在等显示器就绪。所以会认为进程的状态是S。那么我们该如何让进程变成R状态呢?
在这里插入图片描述
在这里插入图片描述
我们可以看到进程的状态是R状态。R状态定义: 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。也就是我们上面所说的运行态
那么S状态也就是我们上面所说的阻塞态。S状态定义:S睡眠状态意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠)。

2.2 D状态

下面继续说明Linux中的D状态。D状态也是一种阻塞态。在Linux中,如果我们等待的是磁盘资源,我们进程阻塞所处的状态就是D状态
举个例子说明一下:
在这里插入图片描述
现在内存中有一个500MB的进程,这个进程需要去磁盘中读写。
在这里插入图片描述
那么此时磁盘开始进行读写,而进程在内存中需要等待磁盘读写的结果(成功or失败),所以进程是S状态。但此时进程越来越多,内存已经满了,操作系统看见此进程是S状态,可能挂起甚至杀掉此进程。
在这里插入图片描述
那么杀了此进程,等磁盘的读写结果出来了,却发现不知道向谁汇报结果。然后磁盘就可能会把此数据丢失。这是非常危险的行为。那么此时有一种方法,就是让进程从S状态变为D状态。
在这里插入图片描述
这样操作系统就杀不了此进程了。
所以,D磁盘休眠状态有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束

2.3 X和Z状态

X死亡状态:这个状态只是一个返回状态,你不会在任务列表里看到这个状态
下面要说的Z状态也叫僵尸状态(zombie)。当一个Linux中的进程退出的时候,一般不会直接进入X状态(死亡,资源可以立马回收),而是进入Z状态
我们知道,进程被创建出来是因为要有任务让这个进程执行。所以当进程退出的时候,我们怎么知道这个进程的任务结果如何呢?所以就需要将进程的执行结果返回给父进程或者操作系统。而Z状态,就是为了维护退出信息(退出信息在PCB里),可以让父进程或操作系统读取

2.3.1 模拟僵尸进程

如何模拟僵尸进程呢?我们可以这样做:如果创建子进程,子进程退出了,但父进程不退出,也不回收子进程。子进程退出之后所处的状态就是Z状态

代码示例:
在这里插入图片描述
这个代码的意思就是子进程就5秒的时间,在5秒后,子进程就退出。但父进程一直在循环不退出。我们来看一下状态:
在这里插入图片描述
我们看到此时子进程和父进程都在,并且两者的状态都是S。
在这里插入图片描述
但是当子进程退出了,但没有回收。父进程没有退出,那么子进程的状态就为Z状态了。

2.3.2 僵尸进程危害

进程的退出状态必须被维持下去,因为它要告诉它的父进程,你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态。
维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护。
那一个父进程创建了很多子进程,就是不回收,进程的相关资源(PCB)不被释放,就会造成内存泄漏。
如何避免?后面讲。

2.4 孤儿进程

我们现在知道父进程不退出,子进程退出不做处理是僵尸状态。那么子进程不退出,父进程退出呢?它就会被称为孤儿进程。那么孤儿进程是什么样子呢?

代码示例:
在这里插入图片描述
现在我们就来看一下运行情况:
在这里插入图片描述
我们可以看到,当两个进程都存在时,它们的状态都是S状态。
在这里插入图片描述
当父进程退出了,我们看到只剩下了子进程。
那么就有一个问题:父进程为什么没有进入Z状态,而是直接没了呢
原因是:我们父进程的父进程是bash,也就是操作系统。而bash可以自动回收,所以父进程结束时,会被bash自动回收。而上面僵尸进程是我们没有写回收方法。

第二个问题:如果父进程提前退出了,子进程还在运行,子进程该怎么办呢
其实子进程会被1号进程领养,而1号进程就是我们的操作系统。

那么现在有一个问题:我们Ctrl+c,不能结束这个子进程了。
在这里插入图片描述
可能细心的同学会发现,本来子进程的状态是S+,然后变成S了。这两者有什么区别呢?带+号的被称为前台进程,而不带+号的叫做后台进程我们现在不知道这个概念,我们要知道后台进程Ctrl+c杀不死。那么我们该怎么办呢?我们可以使用kill -9这个命令。
在这里插入图片描述
此时就可以结束这个进程了,然后操作系统就会自动回收。

2.5 T和t状态

T和t的主要含义是:让进程暂停的意思。

下面就展示一下这个状态:
在这里插入图片描述
我们写一个死循环。
在这里插入图片描述
此时进程一直运行,状态为S+。现在我们想让这个进程暂停,我们可以用命令:kill -19 pid
在这里插入图片描述
此时这个进程就暂停了,那么现在我们就看看这个进程所处的状态。
在这里插入图片描述
此时进程的状态就是T状态。那么我们想继续运行,我们可以用命令:kill -18 pid

那么现在我说一下小t的意义:
在这里插入图片描述
我们gdb调试这个进程,看到此时只有一个S状态的进程。现在我们打个断点,然后再运行。
在这里插入图片描述
此时有一个小t状态的进程。那么小t到底是什么意思呢?其实就是进程被调试的时候,遇到断点所处的状态

3. 进程优先级

首先,我们要谈谈什么是优先级
优先级是进程获取资源的先后顺序

它和权限有什么区别呢
权限是能还是不能的问题,而优先级是能,只是先后的问题

为什么会存在优先级呢
我们知道排队的本质是确认优先级,而需要排队的原因是:系统里进程太多,资源不够。所以进程会竞争资源,所以一定要确认先后。

3.1 查看系统进程

那么我们就用命令的方式来查看进程的优先级:

我们先把准备工作搞好:
在这里插入图片描述
然后我们运行这个程序:
在这里插入图片描述
这个命令我们可以查看进程的优先级。但是这个只能查看当前终端的进程,我们需要加个a,就可以查看所有的进程
在这里插入图片描述
然后我们需要关注这两个PRI和NI。进程的优先级就是看这两个。
PRI :代表这个进程可被执行的优先级,默认是80,数字越小,优先级越高。
但是更改进程的优先级,不是改PRI,而是改NI。
NI :代表进程可被执行的优先级的修正数值。nice其取值范围是-20至19,一共40个级别

所以,PRI(new)=80+nice[-20,19],注意:每次设置优先级,都会恢复成80。

3.2 用top命令更改已存在进程的nice

1. sudo top
2. 进入top后按“r”–>输入进程PID–>输入nice值

大家可以自己试一下。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值