💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶🔹C++🔹Liunx
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
一、状态引入
前面博客中我们学习了什么是进程,其中描述一个进程的结构体——PCB中有如下描述,本篇博客就主要来学习第二行【状态】。
二、操作系统中的状态简介:
就绪状态(Ready):进程已经准备好执行但是还没有被处理器调度执行的状态。
运行状态(Running):进程正在被处理器执行的状态。
阻塞状态(Blocked):进程因为等待某些事件(如I/O操作完成)而被阻塞的状态。
等待状态(Waiting):进程因为等待某些事件(如I/O操作完成、信号等)而被阻塞的状态。
暂停状态(Paused):进程被暂停执行,可以自行恢复执行。
挂起状态(Suspended):进程被操作系统挂起执行,资源被释放,进程状态被保存到磁盘上。挂起状态可以分为内存挂起状态和磁盘挂起状态两种。
终止状态(Terminated):进程执行完毕或者因为某些原因被终止的状态。
三、Liunx中的状态
- 状态的
本质
就是一个在taskt_struct中的整形变量
。 - 状态决定了你的
后续动作
四、Linux进程的七大状态
在linux中一共有如下七种状态,接下来,我们就分别来学习它们吧!
R (running) | 准备好了,随时可被调度 |
---|---|
S (sleeping) | 浅度睡眠;可中断睡眠 |
D (disk sleep) | 深度睡眠;不可中断睡眠 |
T (stopped) | |
t (tracing stop) | |
X (dead) | |
Z (zombie) |
1.运行状态【R】
表示进程正在运行或者正在等待CPU的时间片。
什么是运行状态?
-
一个进程已经准备就绪,可以随时被系统调度此时就是运行状态(千万不要认为被调度执行后才算运行状态)。相当于合并了操作系统的就绪和运行两种状态统称
运行状态
-
如果是一个进程,cpu可能直接就分配足够的资源从而就被执行掉了。但是,当许多进程被调度后,cpu的资源就不够分配了,因为每个进程是需要去竞争CPU资源的浅绿色文字,但是呢CPU不可能同时给这么多进程分配资源,所以,从就绪队列调度后仍然存在一个队列——
运行队列
:(把每个进程的PCB组织起来,就行形成了运行队列[先描述,后组织
]) -
这个运行队列队头指针head所指向就是第一个进程所对应的【task_struct】,队尾指针tail所指向就是最后一个所对应的【task_struct】。所以我们要运行某一个进程只需要将 head 所指向的那个进程放到CPU上去运行即可,但是cpu无法直接找到需要运行的进程,需要借助调度器。具体流程就是,cup->运行队列->调度器。
-
这些存在运行队列中的进程都被称作
运行状态
。 -
时间片:一个进程被拿到cup中执行时,并不是等这个进程执行完毕才切换下一个进程。而是这多个进程在一个时间段内所有代码都会被执行 —— 这就叫做【并发执行】,每一个进程执行一个时间片的时间后就会从cpu上拿下来,然后放上下一个进程。这个动作就称作为【进程切换】。
-
一个时间片通常是
10ms
左右。
原理图如下:
- 补充知识点:虽说是要将task_struct拿去排队,但我们仔细想想,每个进程的task_struct只有一个哟。但是在系统中,一个进程可能不止是在一个地方排队,所以,要解决这种冲突的方法也很简单,就是每个task_struct结构体中都会有很多的structural_listnode n;真正去排队的是这些东西,而不是之前的简化说法PCB。
进入Liunx中:
这里我们使用一个死循环来模拟运行状态 。
#include <stdio.h>
int main(void)
{
while(1);
return 0;
}
make之后,使用ps指令结合head、grep指令筛选出myprocess进程。
从上图可以看出此时的进程状态为【R+】,为什么有个+号呢?
- 这里的
R+
代表的就是这个进程是在前台运行的,所以我们在输入任何指令后不会对其造成 任何的影响。 - 如果想要运行在后台,需要在执行时在你生成的可执行文件后【我的可执行文件是
./myproc
】的后面加上了一个&
;那么其状态变成了R,此代表的意思就是这个进程它是运行在了【后台】的
执行时在末尾加上&
,运行状态如下图为R
学到这里我们也就能理解【为什么运行态是进程正在运行或者正在等待CPU的时间片】了吧
2.浅度睡眠状态【S】(挂起)
——S (sleeping)可中断睡眠状态
进程因等待某个条件(如 I/O 完成、互斥锁释放或某个事件发生)而无法继续执行。在这种情况下,进程会进入阻塞状态,在阻塞状态下,进程不能继续执行,直到等待的事件发生并且操作系统再次将其转换为就绪状态。
♨️什么是阻塞状态?
1.阻塞状态:在CPU的运行队列中就是运行状态,但是这时候你需要访问外设,操作系统就会把你移动到该外设的等待队列,而不是留在CPU的队列中,CPU不会等待你,此时你的状态就是阻塞。
2.阻塞状态下的进程不会占用 CPU 资源,操作系统会调度其他可执行的进程。例如,在调用 sleep
函数时,进程会进入阻塞状态,等待指定的时间间隔过去。
3。阻塞状态就是当前你的状态不能被CPU调度,而是在等待某种资源。我们一会把进程放在CPU等待队列中,一会放在外设的阻塞队列中,其实都是对task_struct对象放到不同队列中。
* 我们的bash,也可以算是一种【阻塞状态】,一直等待着我们去输入命令行,一旦有了的话它就进行读取
* 浅度睡眠可以被信号唤醒:kill -9 PID
1 #include <stdio.h>
2 #include <unistd.h>
3
4 int main(void)
5 {
6 int a = 0;
7 printf("Enter# ");
8 scanf("%d", &a);
9
10 printf("echo : %d\n", a);
11 return 0;
12 }
将该进程运行起来我们可以看到其是出于S+的状态,因为【shell】此时正在等待用户的输入,遇到I/O操作。
- 可以使用
kill -9 PID
杀掉它,也就是激活
。下面讲的深度睡眠状态不能通过操作系统将其杀掉的,而是要等到磁盘写入完毕或者什么事情执行完毕后其才会去自动结束这个进程,或者是在外部断电、直接拔掉电源即可
3.深度睡眠状态【D】
——D
(disk sleep)深度睡眠状态
深度睡眠状态
:处于 D 状态的进程。这意味着进程正在等待事件发生,而且不能被任何信号唤醒,除非是设备断电了等物理因素。
为了更好理解深度睡眠,我引用一篇博客中的例子:
-
1.现在在操作系统里有一个进程,它呢想要把数据写到磁盘上去,磁盘这个时候听到了它的请求,就开始写数据,不过我们知道外设尤其是像磁盘这种设备的速度都是比较慢的,所以呢这个时候进程就会一直地等待下去
-
2.但是呢,光这么无休止地等待下去可不行。因为当前这个时候操作系统中的已经有非常多的进程了,那么OS它看不下去了,路过的时候看到当前的这个进程正处于等待状态,也不运行,于是二话不说把它终止了
-
3.所以呢,同学们,我们要明白这么一个道理:操作系统认为当前系统能行的话就直接让用户去用就可以了,如果扛不住了就置换页表,实在不行了就去会杀进程。
-
4.造成严重问题:那么当这个进程被杀掉的时候,磁盘说:我在写数据的时候出了问题。它这个时候就回去找那个调度它的进程,但是发现这个进程没了???所以磁盘就特别尴尬:我要怎么办呢?写好的这个数据该不该还放在这里【一般的设备都会选择丢失】如果这份数据是普通的那还好,但如果其为银行当中那种非常重要的数据呢
🚩如何解决呢?
-
在上面例子中,操作系统会在内存压力很大的情况下,杀死掉哪些一直在进行等待的进程。但是,杀死进程可能会引发严重后果,所以,最好的办法就是【让该进程拥有一块
免死金牌
】 -
图也是很搞笑-_-
-
这个免死金牌具体来说就是给该进程的状态设置为
深度睡眠状态
。那么这个进程就不会被杀死了,当磁盘写完数据后告知进程,那么它就可以将自己放入【运行队列】里去运行,此时它的状态就变成R了
📅事务总是具有两面性:
抛出问题:那这个时候就又有同学问了:D状态这么强大吗,那如果一个操作系统里有很多的D状态,这怎么办呢?
1️⃣ 这个D状态的话操作系统是没有办法将其杀掉的,而是要等到磁盘写入完毕或者什么事情执行完毕后其才会去自动结束这个进程,或者是在外部断电、直接拔掉电源
即可
2️⃣一般一个系统里面如果存在D状态的话,那这个系统中的磁盘压力已经非常大
了;如果存在多个D状态的话,则表示这个系统已经是非常危险了,最好马上重装一下系统
4.停止状态【T】
——T (stopped)停止状态
在Linux中,"停止状态"通常指的是进程的一种状态,也称为"停止"或"暂停"状态。当一个进程被挂起或暂停时,它会停止执行,并且不再消耗CPU资源。
这种状态通常发生在以下情况下:
当进程读取一个设备,但是被设备拒绝了,而操作系统又不想杀掉你,此时,为了减少你的非法操作,就会把该进程置为停止状态。
当用户使用Ctrl+Z组合键将一个正在前台
运行的进程移至后台
时,该进程会进入停止状态。
指令:
- 系统管理员可以使用kill命令的-STOP选项,或者kill -s SIGSTOP命令,将一个进程暂停。
- 在停止状态下,进程仍然存在于系统中,但不再活动。可以使用fg命令将一个停止的进程移回前台继续执行,或者使用bg命令将其放入后台执行。
暂停进程:kill -19
PID
启动进程:kill -18
PID
暂停状态的理解:
处于暂停状态的进程,不仅仅是等待硬件资源,也可能是等待软件信号等,所以,他也可以被看作是一个阻塞状态的分支。
🅿️区别:这个T停止状态和S睡眠状态有什么不同呢?
Linux中的停止状态和浅度睡眠(挂起)状态是两种不同的状态,它们有以下区别:
T停止状态和S睡眠状态在Linux系统进程管理中有着不同的含义和特性:
1️⃣ T停止状态(stopped):
- 当一个进程处于T状态时,它已经被停止执行。这通常是通过向进程发送SIGSTOP信号来实现的。
在T状态下,进程不会执行任何代码,也不会响应任何信号(除了SIGCONT)。
如果想要让处于T状态的进程继续执行,需要向它发送SIGCONT信号。
T状态通常用于调试或暂停进程的执行。
2️⃣ S睡眠状态(sleeping):
- 当一个进程处于S状态时,它正在等待某个事件或资源的完成。这可能是由于多种原因,例如等待I/O操作完成、等待某个信号、等待锁等。
在S状态下,进程不会执行任何代码,但它会响应某些信号(如SIGKILL或SIGSTOP)。
当等待的事件或资源完成后,进程会自动从S状态恢复到运行状态(R状态)。
S状态是进程管理中非常常见的状态,因为许多进程都需要等待某些条件满足后才能继续执行。
3️⃣ 总结来说,T停止状态和S睡眠状态的主要区别在于:T状态是进程被显式停止执行的状态,需要通过发送信号来恢复;而S状态是进程在等待某个事件或资源完成的状态,当等待条件满足时进程会自动恢复执行。这两种状态在Linux系统进程管理中都有重要的作用。
5.进程跟踪状态【t】
在 Linux 中跟踪停止是一项功能,允许您停止进程运行,然后稍后恢复它。这对于调试或解决进程问题非常有用。该信号将使进程处于停止状态。该进程不会使用任何 CPU 资源,但仍会使用一些内存资源。您可以通过向其发送信号来恢复该过程
在 Linux 中,调试器 (如 GDB) 可以通过调用 sigpause 信号来暂停正在运行的进程。当进程接收到这个信号时,它会立即被停止,并且所有正在运行的进程将被挂起,以便调试器可以访问进程的内存和其他资源。
当进程被追踪停止时,它的状态将显示为 “t”,同时进程的 PID 值将被标记为 “tracing stop”。此时,进程将不再执行,而是停留在执行点,以便调试器可以访问进程的内存和其他资源。如果进程正在被调度器调度,那么它将被标记为 “stopped”,并且在调度器的保护下不会被其他进程抢占。
需要注意的是,“tracing stop” 状态只在特定条件下出现,例如在使用 GDB 调试进程时,或者在内核中启用了调试器支持。通常情况下,用户不应该在正常运行的系统中启用追踪停止功能,因为这可能会导致系统崩溃或数据丢失。
6.死亡状态【X】
进程已经使用完毕了,所以让
进程退出
,并且把所进程占用的资源全部释放
。(一个人去世后,把他埋葬,处理好他的后事)
1.第一种方法就是向这个进程发送9号信号,就可以杀掉这个进程
kill -9 PID
2.第二种方法就是通过这个进程的名称来杀掉它
killall 进程名
注意:kill千万不要被它的名字觉得这个指令就是杀死进程的指令。kill的真实作用就是向进程发送信号的,不止是有 -9选项,它有许多选项。对应着不同的作用。
7.僵死状态【Z】
进程使用完毕了,并且进程也退出了,但进程占用的资源没有被完全释放。(一个人去世后,没有将他埋葬,没有处理他的后事)
这一状态,涉及到的东西很多,后期单独写一篇博客进行讲解。