前言:在进程学习这一块,我们主要学习的就是PCB这个进程控制块,而PBC就是用来描述进程的结构体,而进程状态就是PCB结构体中的一个变量。
本篇主要内容:
- 操作系统中的进程状态
- Linux下的进程状态
在开始之前,我们先来简单了解以下进程状态
进程的本质就是PCB中的一个变量!!!
所谓状态变化,本质就是修改整形变量!!!
1. 操作系统中的进程状态
本篇围绕操作系统中的三种进程状态:运行状态
,阻塞状态
,挂起状态
来展开
当进程准备好了随时可以被调度时,其实就是创建状态和就绪状态,这俩没有太大区别!!
运行状态
虽然不同的计算机有不同的配置,但是无论如何
每个CPU都会在系统层面有属于自己的运行队列!
只要在运行队列中的进程都是运行状态!
阻塞状态
我们在编写的代码中,都会无法避免的访问一些操作系统里的某些资源,比如:磁盘,键盘,网卡等硬件设备,当我们用scanf或者cin读取键盘数据时,当我们不输入s时,数据没有准备就绪,进程不具备访问条件,进程代码无法向后执行,这就是阻塞状态
系统会等待用户输入,只要不输入,要访问的资源就没有就绪
比如:
1 #include<stdio.h>
2
3 int main()
4 {
5 int n = 0;
6
7 printf("please Enter# ");
8
9 scanf("%d",&n);
10
11 printf("echo# %d\n",n);
12
13 return 0;
14 }
我们在运行这段代码时;
进程一直等待着我们从键盘输入数据,此时进程就处于阻塞状态!
操作系统要管理进程,操作系统就必须知道进程的基本信息;操作系统要管理硬件,也就必须知道硬件的相关信息!
那操作系统是如何知道底层硬件的信息呢?
在操作系统中,有管理设备的结构体
将一个进程从运行队列移动至的等待队列中,再将状态改为阻塞那么这个进程就处于阻塞状态,这个过程就是状态变化!
进程状态的变化:
- 更改
PCB status
的整数变量- 将PCB连入不同的队列中
所有过程都只会进程的PCB有关,和进程代码数据没有关系!
操作系统中,会存在非常多的队列,运行队列,等待硬件的设备等待队列等,并且所有系统内的进程都是以双链表链接起来!
挂起状态
假设:
一个进程当前被阻塞了,那么这个进程在它所等待的资源没有就绪的时候,该进程是无法被调度的。如果此时恰好OS内的内存资源已经严重不足了,那么操作系统该怎么办?
- 因为此时进程处于阻塞状态,并且内存已严重不足,所以OS会将PCB对应的数据和代码转移到磁盘,为内存释放一部分资源,腾出一部分空间,然后该进程就被挂起了
- 将内存数据进行置换到外设,针对所有阻塞进程,因此不用担心效率降低的问题,因为这个是必然的,而现在首要任务是让操作系统能继续执行下去!
- 分区是磁盘中真实存在的,它的大小往往是很小的,这个部分专门
用于内存严重不足时和内存进行交互,并且当内存情况缓解后,曾经被置换出去的代码和数据又会重新加载进来- 当进程被系统调度时,曾经被置换出去的进程代码和数据,又要重新被加载进来
2. 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下的进程状态:
- R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
- S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
- D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束。
- T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
- X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态
运行状态
在介绍完这些状态之后,我们来实际操作看看!
我们来一段死循环代码,方便我们观察
1 #include<stdio.h>
2 #include <unistd.h>
3 int main()
4 {
5 while(1)
6 {
7 printf("hello , Linux!\n");
8 sleep(1);
9 }
10 return 0;
11 }
~
我们可以看到程序时处于一个
S+
的状态,但是依据概念,程序不应该是R
状态吗?
- 因为循环打印时,IO输出是很慢的打印字符会和外设屏幕交互,因此大部分时间进程都处于阻塞状态,但也有极少时间在打印,所以查看进程状态时,我们偶尔可以看见
R
状态
如果我们将printf
删除,单留while
,会是什么情况呢?
1 #include<stdio.h>
2
3 int main()
4 {
5 while(1)
6 {
7 }
8 return 0;
9 }
我们可以看到此时程序处于R
状态
休眠状态
- S(sleeping):休眠状态,浅度睡眠,可以被终止,浅度睡眠会对外部信号做出响应
- D(disk sleep):也是休眠状态,深度睡眠
S相对操作系统来讲也就是阻塞状态,D则是专门针对磁盘设计的
我们来换个角度来理解以下D状态:
- 假设在内存中,有一个进程,需要将自己的代码和数据写入磁盘,因为内容数据不小,在磁盘拷贝时,需要一段时间,此时进程变为S状态。
- 此时,恰好系统内的内存资源已经严重不足了,系统压力太大,Linux在是在没办法时候,会通过杀掉进程,节省资源的,来不及进程反应直接被系统 “干掉” 。
- 然后磁盘写入失败,而磁盘也有自己的事情要做,然后将未完成的代码和数据直接删除,拷贝失败!
如果真是这样,下次是很重要的数据,那么损失不可估量
因此系统创造了D
状态:磁盘休眠状态;D
状态不可被杀掉,OS也没有权力!
综上:
S
状态可以被终止,D
状态不可被终止!
前台进程和后台进程
刚刚在上面查看进程状态时,是否有过疑问,为什么进程状态后面会有一个加号呢?
其实加号表示的是前台进程,而没有加号则是后台进程
我们先来了解一下这两种进程:
- 前台进程:运行时无法使用bash外壳的指令并且可以被ctrl + c 强制终止
- 后台进程:运行时可输入指令,不能被ctrl + c 终止只能使用kill指令来杀掉进程。
程序默认是前台进程,那么我们怎样才能将前台进程变成后台进程?
在执行程序时在末尾加上&
通过视频我们来更直观的了解二者的区别
后台进程与前台进程
停止状态
- T (stopped) 在进程访问软件资源的时候可能暂时不让进程进行访问,就将进程设置为STOP
- t (tracing stop) debug程序的时候,追踪程序,遇到断点,进程暂停了
下面我们来看两个视频理解以下:
kill指令停止进程
SIGSTOP与SIGCONT
调试遇到断点
查看t状态
二者都是停止状态,对于停止状态用到的不多,我们了解一下即可!
3. 总结
在了解Linux中进程的分类时,我们通常是先了解操作系统的进程,因为二者有一定的联系,了解操作系统能更好理解进程在操作系统中的运行关系。进程状态在进程中也极为重要,希望大家能理解透彻!
谢谢大家支持本篇到这里就结束了