这里我们终于开始进程本身的内容了,我们之前讲操作系统管理的是进程的PCB块,那么很显然,进程状态就是PCB中的一个变量,可以使用宏定义来实现
#define NEW 1
#define RUNNING 2
#define BLOCK 3
struct PCB
{
// ...其他配置
int state; // 进程状态
}
这里我们主要介绍三种操作系统进程状态,分别是运行状态、阻塞状态、挂起状态,并且讲解Linux中具体的进程状态,分别是R状态(运行状态),S状态(睡眠状态)
操作系统进程状态
运行状态
现在我们使用的电脑和手机CPU说是8核心,16核心,也就是相当于CPU可以分别同时处理多个任务,我们为了方便称之为小CPU,每一个小CPU都有其对应的运行队列,他会从自己的运行队列中寻找数据来进行处理,但这里有一个容易混淆的点,就是无论这个进程是否被处理,只要他处于运行队列中,他就是运行状态
例如
以上的PCB1到PCB5,全都是运行状态
阻塞状态
我们先不去深究阻塞状态究竟是什么,先从感性上感受一下
当CPU处理一个进程时,或多或少都会访问一些外部设备,例如磁盘、网卡、键盘等
例如当你在代码中写了一个cin或者scanf的时候,系统就会等待用户输入,只要用户不输入,要访问的资源就没有就绪,此时代码就无法继续运行下去,那这个进程就处于阻塞状态,了吗??
对但不完全对,我们从操作系统的视角来看这个问题
还是之前我们所说的,想要进行管理这个操作,就要两步走,先描述、后组织
那么管理设备,也应当有一个结构体,这样操作系统才能通过访问结构体来得知设备状态,也就是这个设备是否具有访问条件,是否就绪
每一个设备的结构体中有一个独属于他的等待队列PCB* wait_queue
当一个进程从运行队列移动到某设备的运行队列中,再将进程的状态改为阻塞,此时这个进程就处于阻塞状态
每个CPU或者设备都有自己的队列,而进程状态能够变化的本质就是将PCB链接到不同的队列当中,并改变PCB中表示进程状态的变量
挂起状态
我们知道,进程是需要消耗内存资源的,尤其是当进程处于阻塞状态时,他又不继续运行,又消耗内存资源
当内存资源严重不足并且有大量进程处于阻塞状态的时候,操作系统就会将这些PCB对应的数据和代码给搬到磁盘去,腾出内存让系统不至于卡死,那么这些个被搬到磁盘去的PCB,就是处于挂起状态的
在磁盘中的这部分分区是swap分区
需要注意的是,将内存数据放到外设上,是针对所有的阻塞进程的,并且这时候其实不用关心效率高低,因为如果不这样做操作系统就挂了
除此之外,swap分区在磁盘中是真实存在的,而且他的大小不会很大,主要是为了拯救一下操作系统,当内存情况缓解之后,就会被重新加载到内存
Linux的进程状态
这里是在Linux中的进程状态
/*
* 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和S状态
首先来看看我们可以在哪里看到进程状态
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("这是一个进程");
sleep(1);
}
return 0;
}
这里我们可以看到STAT一栏下面是S+,诶很奇怪,明明这是一个运行中的程序,但为什么却是S状态
这是因为屏幕循环打印,CPU处理这个循环其实很快,但是字符显示到屏幕上却很慢,因此程序大部分时间都处于阻塞状态,如果这时候一直打印查看状态,我们将看到这个程序大部分时间都处于S状态,可能百分之一的时间是R状态,而如果这个程序什么也不打印,那么他将会一直处于R状态
前后台进程
我们之前在将kill命令杀进程的时候说到过,后台进程不能通过ctrl +c
来结束,只能通过kill命令来杀进程
当我们想要一个程序在后台运行的时候,只需要在运行时加上&
即可
例如./a.out &
休眠状态与磁盘休眠状态
细心的同学发现这个进程状态有两个sleep
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
我们将S状态称之为浅度睡眠,D状态称之为深度睡眠
当我们从网络上下载资源时,会遇到文件很大,下载时间很长的情况,如果这时候内存突然不够,操作系统还恰好把这个很重要的下载进程干掉了,那岂不是闯大祸了,为了防止这种在向磁盘写入重要数据时被杀掉的情况,就有了D状态
在S状态下,程序是处于浅度睡眠,是可以被主动终止的,而在D状态下,是无法被终止的程序,某些情况下甚至连断电都无法终止,除非扣主板电源()
除此之外还有一些有意思的概念,例如僵尸进程、孤儿进程,我们会在下一节的进程优先级中一并介绍