进程状态模型

二状态模式

该模型将进程所处的状态划分成:运行态、未运行态。
在这里插入图片描述

五状态模型

如果系统中所有的状态都做好了执行准备,那么上面的模型是有效的。但是这样的模型过于简单。设想,如果队列中有一个进程因为等待某个事件就绪,而处于阻塞态……那就巴比Q了

所以为了更加合理、且高效地利用CPU资源,我们应该将进程所处的状态细化。就好比,学校跑步测试,运动员的状态被划分为就绪状态、未就绪状态,跑步状态、考完状态……,如果运动员处于考完状态、那么就不用管他了,如果运动员处于就绪状态,就准备让他先跑……这样就能根据运动员的状态来最高效地利用测试资源。

在这里插入图片描述

接下来我将继续使用跑步测试的例子讲解。

五状态模型把进程所处状态划分为:

  • 运行态
  • 就绪态
  • 阻塞态
  • 新建态
  • 退出态

运行态:
该进程正在执行。好比跑步测试时,运动员正在跑步。

就绪态:
该进程的条件已经准备好,做好了被执行的准备。好比跑步测试,测试时的各种条件都准备好了,运动员也准备好了测试,只等待跑步开始。

阻塞态:
进程在某些事件发生前不能执行。好比跑步测试,你需要带上测试的衣服才能去准备区等待,但是体育老师还没有给你发放,而你没有穿测试的衣服,所以还不能准备跑步。

新建态:
也称初始态,指的是进程才被创建好,但是还没有加载到主存储器里。好比跑步测试,你刚刚才报名的跑步测试,学校还没有为你准备,也没有把你的资料传给负责这跑步测试的人/组织。

退出态:

在这里插入图片描述
【进程模型中的队列】
处于就绪态的进程被放入:运行队列、又可以称为就绪队列。
处于阻塞态的进程被放入:阻塞队列,又可以称为等待队列。

七状态进制模型

利用五状态模型已经能很好地利用CPU的资源了,但是还可以更进一步地优化。

模型中的处于其中四个状态的进程都被加载到内存里面了,设想:系统中此时如果同时存在大量的进程,然而内存(主存)存储空间是有限的,远远没有外存的存储空间大。就极大可能存在,一些在等待某些事件发生的进程一直占据着内存空间,导致很多处在外存的进程不能加载到内存里,因为已经没有容纳这些进程的存储空间。

以上的解决办法有两种:

  • 🥣增加主存容量
  • 🥣交换空间。

推荐第二种方法。

在这里插入图片描述
交换空间,实质把主存中的把空间腾出来,让给那些还没有加载到主存的进程。

相当于是把让某些进程晾在一边(挂在一边),让它在外面等待某些事件发生,或者让它在外面等待被执行。好比跑步测试时,操场的容量是有限的,可以让操场里还没有做好准备或者等待着某些事件发生的运动员,转移到操场外面,而让操场外面有条件的运动员转移到操场上。
这些进程所处的状态就变为“就绪/挂起态”,或者“阻塞/挂起态”。
【区分】
🍭就绪态:进程被加载到主存里,在运行队列(就绪队列)中,随时准备被执行
🍭阻塞态:进程被加载到主存里,在等待队列(阻塞队列里)中,等待着其他必备事件的发生。

🍭就绪/挂起态:进程在外存(辅存)里面,在挂起队列中,等待着其他必备事件的发生。
🍭阻塞/挂起态:进程在外存(辅存)里面,在挂起队列中,随时准备加载到主存里执行
在这里插入图片描述

挂起状态的进程特点:
1.不能被立马执行
2.在等待某些事件的发生
3.不想被执行。

第三个特点是很巧妙,不想被执行的进程可以把它转变为挂起进程,通过代理(进程本身、父进程或者操作系统),把它的状态转变为挂起状态,一旦被转变为挂起状态,就不能从这个状态转换成其他状态,除非代理显示地转化该进程的状态。

Linux中的进程状态

上面所述的二状态进程模型,五状态进程模型,七状态进程模型,是系统的基本进程状态的模型,既然是模型,那么不同的操作系统可能会略有不同,一起看看Linux操作系统的各种进程状态吧。

下面是Linux描述进程状态的结构体,这个结构体在Linux的进程控制跨块task_struct

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
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 */
};
  • R: 理解为Running,代表运行状态. 这里的R对应模型中的等待状态/运行状态

  • S :理解为sleeping的缩写,代表睡眠状态.对应模型中的阻塞状态,他必须等待事件。

  • D:理解disk sleep的缩写,代表深度睡眠状态。是因为受到内核指示而停用的睡眠进程,外部信号无法唤醒它们,只能有内核来亲自唤醒

  • T:stopped的缩写,代表暂停状态。进程特意停止运行的状态,比如调试器暂停来进行调试操作的时候。

  • t:tracing stop的缩写,它本来不是一个进程的状态,就是用来区分处在暂停状态的进程,看它是否是被调试的进程还是常规的暂停。

  • Z:zombie的缩写,代表僵尸状态

提到僵尸我也看过很多僵尸片了,按照我们的说法,僵尸的特点是,它既死了又活着,只不过是没有灵魂的活着 。而僵尸状态的进程也是如此,这个进程即死了又活着。说它死了是因为它的资源已经被释放了,那么也就不能再次运行;说它活着,是因为进程表里面还有它的PCB,也就是还含有这个进程的各种属性信息。它没有真正地被终止。

判断一个程序是不是真正地终止或者退出了,要看两个方面
1】程序被另一个进程或一个用户杀死
2】内核已经释放为进程保留的资源。

当一个条件符合,而第二个条件不满足时,那么就会出现僵尸状态。

在这里插入图片描述

  • Z:死亡状态。真正地终止了

接下来看一看Linux中进程的各种状态吧。

现在有如下程序

//mycode.c文件
1 # include <stdio.h>
2                                                                             
3 int main(void)
4 {
5   while(1)
6   {
7     ;
8   }
9   return 0;
10 }

开始在终端执行这个程序。
复制会话,然后查看该进程
在这里插入图片描述
发现它一直处于R状态。

//mycode.c
  1 # include <stdio.h>
  2 
  3 int main(void)
  4 {
  5   while(1)
  6   {
  7    printf("hello\n") ;                                
  8   }                           
  9   return 0;                   
 10 }  

但是现在在运行,会发现它大多数时候都是S状态,这是因为涉及到了IO操作,相对于CPU来说,IO简直太慢了,所以这个进程大多数都在等待IO设备的就绪。

其他的你们自行测试吧。
【孤儿进程】
还有一种特殊的进程,孤儿进程。
孤儿进程,当一个进程的父进程,在该进程还没有终止前父进程就提前终止了,那么该进程就变成了孤儿进程,孤儿进程会被init进程(1号进程)“领养”
在这里插入图片描述

Logo

更多推荐