进程状态(二)----- linux 中具体的进程状态(上)

outlier.cc 2024-08-31 11:37:02 阅读 95

目录

前言1. R 状态2. S 状态3. D 状态

前言

继上一篇文章 进程状态(一)---- 运行,阻塞,挂起 介绍了操作系统都有的三个进程状态,而这篇文章则是将进程状态具象化,谈论具体到 linux 系统中的进程状态都有哪些。

<code>/*

* 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 */

};

1. R 状态

既然要了解某一种状态,那么肯定要先见一见吧。亮出我们的测试 demo

int main()

{

while(1)

{

cout << "hello, linux! \n";

sleep(1);

}

return 0;

}

在这里插入图片描述

很奇怪的是,按照我们正常的理解,我们明明已经将这个程序运行起来了,这个进程也一直在执行中。但是,查到的状态确实 S+,而并不是 R 状态!

<code>int main()

{

while(1);

return 0;

}

在这里插入图片描述

而当我们执行这一份代码的时候,就会发现,这个进程运行起来的时候,检测到的状态是 R+ 状态!(这里先解释一下,+ 号的含义是前台运行,而不带 + 号则代表该进程处于后台运行,前台运行可以理解为,如果此刻你不关闭这个进程 或者将进程转为后台工作,在命令行中你是无法执行其它指令的。后台运行类似 <code>./test &)

所以这种想象是为什么呢??这个进程明明正在执行,但是却出现了两种截然不同的状态! ---- 原因就是第一个 demo 里面涉及到了打印操作,那么它就需要访问外设资源,也就是往显示器进行写入。但是,现在的问题就在于,外设不一定一直处于就绪状态,所以对于进程而已,它其实很大概率一直处于一个等待外设资源的状态!而在上一篇文章,我们说了,进程在等待某种外设资源的时候,称为阻塞状态!而当我们把 cout 去掉之后,不再需要进行 IO 操作了,就是纯粹的条件判断,这是 cpu 需要做的工作,所以这个进程就一直处于死循环的判断中,检测到的状态就是 R 状态,即运行状态!

2. S 状态

那在 linux 中什么是 S(睡眠) 状态呢?在介绍 R 状态的时候,误打误撞的发现了一个正常运行的进程,处于 S 状态,但是那个例子还不足生动的解释什么是 S 状态。

int main()

{

int a;

cout << "Enter: ";

cin >> a;

cout << a << endl;

return 0;

}

在这里插入图片描述

如图,当我进行 scanf 或者 cin 读取键盘数据时,但是我现在就是迟迟不输入,不回车,那么进程此刻就一直处于等待键盘设备资源的状态!而这个状态与介绍 R 状态时的等待外设资源是一样的,只不过上面那个案例,进程一直在运行,给我们的直观感受就是 R 状态,只不过是因为 cpu 与 外设的速度达到的 10^6 量级,这么大的差距下,进程 99.99999% 都是在等待外设资源,只有那 0.0000001% 是在被 cpu 执行(处于 R 状态),而现在这个案例,只不过是干脆将进程卡住了,只要我们不输入,它就会一直处于等待键盘设备资源中,而进程被卡着不被执行,处于等待某种资源状态,在操作系统中,我们称为阻塞状态,而具体到 linux 系统中,这种阻塞状态就是 S 状态!

3. D 状态

在前言部分的 linux 源码中,我们就看到了 S 是 sleep,D 也是 sleep(disk sleep),那这两种都是睡眠状态,有什么区别吗?? ---- 字面上的区别就是,D 是深度睡眠(也称为磁盘休眠),那么既然有深度睡眠,你也可以将 S 解读为 浅度睡眠。

而上面所展现出来的 S 状态的进程,它们都是可以被唤醒的(只要等待资源就绪了,立马就可以被唤醒),同时它也是可以被 <code>kill -9 杀掉的。既然都是睡眠,D 状态肯定要与 S 状态不同,所以不同点在哪呢?我们讲个故事。。。

假设今天内存中有一个进程,它现在正在尝试往磁盘写入 500M 的数据,所以进程就呼喊了在远处的磁盘 “磁盘,我这有 500M 的数据,你帮我写一下”,磁盘听到进程的呼唤后 “行,你把数据给我吧”,之后磁盘就去找一个足够容量 500M 数据的位置,把数据给进程写入到磁盘中,写完之后再把结果回去反馈给进程(写入成功还是失败)。而磁盘写入,是需要时间的,换句话说,在磁盘写入的过程中,进程是需要等待磁盘的,等磁盘把数据都写完了,然后拿到磁盘的反馈结果之后,再去干其它的工作。所以磁盘在写入的时候,进程就在内存中翘着腿,喝着茶,嘴里还哼着歌。。。

很不巧,现在计算机因为各种原因处于高负载状态,系统进程非常多,系统中的内存资源严重不足了,操作系统正在忙的焦头烂额,正在绞尽脑汁的腾出内存资源,操作系统把所有可以置换的进程都置换了(处于等待队列中的进程,将这些进程所对于的代码和数据换出到磁盘中),内存资源还是处于不足状态,突然间路过看到内存中有一个翘着腿、喝着茶,嘴里还哼着歌的空闲进程!

而此时,操作系统中的内存资源越来越吃紧了,操作系统心理也憋着一股气 “我tm在这累死累活想办法腾出内存资源,你不仅占用我资源,还在这啥都不干,给我gun!”,于是操作系统直接把这个进程杀掉了。而进程被杀掉之后,磁盘写入到一半发现没空间了,于是想回来找到进程,并且将结果反馈给进程。但是,磁盘此刻傻眼了,因为哪还有它要找的那个进程。磁盘心理想着 “so?爱会消失吗?说好的你等我?”,磁盘也不知道怎么办了,因为它只是负责写入数据,它并不知道该如何决策这件事啊。

而面对上述情况,不同的硬件的做法可能都不一样,大部分的硬件都是选择直接丢弃数据。很不幸,这波数据存储着银行上百万条转账记录,价值高达10个亿,于是法官出面了,而众多舆论都直接指向了操作系统,大家都认为是操作系统杀掉了进程才导致的悲剧。

所以操作系统就出面询问了法官 “ 请问用户是不是赋予我管理软硬件资源的权力了?请问我杀掉进程是不是在极端情况下做的?请问我这是不是在履行我自己的义务?我总不能因为这一个进程,导致操作系统奔溃了,最终所有的进程都挂掉了吧?操作系统都挂了,那其它进程的数据还是会丢,那这样损失岂不是更大?”

法官听闻,点了点头(有道理),于是法官就看了一眼磁盘 “数据是你写的,数据也是你丢的, 你有什么想说的吗?”

磁盘顿时抖了个机灵 “法官大人,我只是一个跑腿的啊,人家叫我干嘛,我就干嘛,进程叫我帮它把数据写了,我告诉它在那等我消息,而我回来之后我找不到进程了啊,但是我的工作模式就是这样的,写入失败了,进程又不在了,我怎么知道这些数据我要怎么办呢?如果今天我有罪,那么岂不是所有的磁盘都有罪。”

法官听闻也是点点头(这货说的也有道理),于是法官大家想着,既然操作系统没错,磁盘也没错,那有错的总得是你进程了吧?

进程心理一百只马路过,“我明明是受害者,我都被杀掉了,现在我还有错了?天理不容啊!”

法官听闻陷入了沉思,好像大家说的都没问题。

所以因为可能存在上述情况,于是操作系统在设计的时候,就规定了只要某一个进程当前有写入任务,并且无法一时间得到磁盘的响应,需要进程等待,这个进程不能以浅度睡眠(即 S 状态)存在于操作系统中,需要将其设置为 D 状态,并且规定,任何人(包括操作系统),不得以任何理由杀掉正在处于 D 状态的进程。

所以!当进程处于等待磁盘写入时,此时进程所处的状态为 disk sleep,即 D 状态!

但是你要知道的是,D 状态代表着 高 IO,在系统中哪怕出现一个 D 状态的进程,你的操作系统就已经快要奔溃,而当被用户发现系统中有一个 D 状态的进程,就说明这个状态已经维持了一段时间了,用户的感知级别是 秒为单位的,而慢如磁盘等外设,怎么说也是毫秒,cpu 更是以纳秒为单位,因此如果到了连用户都能察觉的程度,你的系统八九不离十,距离奔溃就只差几个呼吸了。所以一般情况下,就算有 D 状态的进程,维持时间也是很短的。


由于篇幅过长等问题,linux 中还有关于进程的其它三个状态,分别是 T && t 状态,X 与 Z 状态,还有所谓的僵尸进程,孤儿进程,这些状态之间都有什么不同,在下一篇文章 进程状态(三)----- linux 中具体的进程状态(下) 都会进行一一介绍。

如果感觉该篇文章给你带来了收获,可以 点赞👍 + 收藏⭐️ + 关注➕ 支持一下!

感谢各位观看!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。