进程状态
💦 进程状态
1、Linux 2.6内核源码
后期我们主要也是以 Linux 2.6 为主来学习,因为它匹配的书籍较多。
其中 task_state_array[]
里描述的是 Linux 的进程状态:
2、R (running)
进程是 R 状态,一定在 CPU 上运行 ❓
进程在运行队列中,就叫做 R
状态,也就是说进程想被 CPU 运行,前提条件是你必须处于 R
状态,R
:我准备好了,你可以调度我。
为啥我在跑,但状态却是 S ❓
因为代码大部分时间是在 sleep 的,且每次 1 秒钟,其次 printf 是往显示器上输出的,涉及到 I/O,效率比较低,一定会要求进程去等我们把数据刷新到显示器上。所以综合考量,我们这个程序可能只有万分之一的时间在运行,其它时间都在休眠,站在用户的角度它是 R,但是对于操作系统来说它不一定是 R,它有可能在队列中等待调度。
如果我们就想看下 R 状态呢 ???
循环里啥都不要做。
3、S (sleeping)
休眠状态(浅度休眠,大部分情况)
。这种休眠是可被换醒的,我们可以 Ctrl + C 退出循环,而此时的进程就没了,也就是说它虽然是一种休眠状态,但是它随时可以接收外部的信号,处理外部的请求。
4、D (disk sleep)
休眠状态(深度休眠)
。
此时进程拿着一批数据找到了磁盘说:磁盘,你帮我把数据放在你对应的位置。磁盘说:好嘞,然后磁盘就慢慢地写到对应的位置。此时进程处于等待状态,它在等把数据写完,然后告诉进程写入成功 or 失败。此时操作系统过来说:你没发现现在内存严重不足了吗,我现在要释放一些闲置的内存资源,随后就把进程干掉了。磁盘写失败后,然后跟进程说:不好意思,我写失败了,然而进程已经挂了,此时我们的数据流向就不确定了。
对于上面的场景,这个锅由谁来背 —— 操作系统/内存/磁盘 ❓
于是它们三方开始了辩论:
操作系统说,你在那等,我又不知道你在等啥,系统内存不足了,我就尽我的职责,我的工程师就是这样写我的,杀掉闲置的内存。假如我这次不杀你,那你说下次我再遇到一些该杀死的闲置的内存,我怕我又被责怪,所以没杀,你就认为我不作为 ?操作系统说:我又识别不了哪些进程是重要或不重要的。
磁盘说,我就是一个跑腿的,你们让我干啥就干啥,又不是写入的结果不告诉你,而是你不在了。
进程说,我在那规矩的等着呢,是有人把我杀了,我自己也不想退出。
这里好像谁也没有错,但是确实出现了问题,你难道说错的是用户 —— 内存买小了吗 ?无论是操作系统、内存、磁盘都是为了给用户提供更好的服务。根本原因是操作系统能杀掉此进程,如果让操作系统不能杀掉此进程就可以了。我现在做的事情很重要,即便操作系统再牛,也杀不了我,你系统内存不够了,你想其它办法去,不要来搞我。所以我们针对这种类型的进程我们给出了 D 状态,所以操作系统从此就知道了以后 D 是个大哥,不能搞。
所以对于深度睡眠的进程不可以被杀死,即便是操作系统。通常在访问磁盘这样的 I/O 设备,进行数据拷贝的关键步骤上,是需要将进程设置为 D 的,好比 1 秒钟内,平台有 100 万的用户注册,如果数据丢失,那么带来的损失是巨大的。
对于深度睡眠的进程怎么结束 ???
只能等待 D 状态进程自动醒来,或者关机重启,但有可能会卡住。深度睡眠的进程我们没法演示,万一把自己的机器玩挂了,成本较高。
不管是浅度睡眠还是深度睡眠都是一种等待状态,因为某种条件不满足。
5、T (stopped)
对于一个正在运行的进程,怎么暂停 ❓
使用 kill -l
命令,查看信号,这里更多内容后面我们再学习:
使用 kill -19 27918
命令,给 27918 进程发送第 19 号信号来暂停进程:
使用 kill -18 27918
命令,给 27918 进程发送第 18 号信号来恢复进程:
我们也可以认为 T 是一种等待状态。
6、T (tracing stop)
当你使用 vs of gdb 调试代码,比如你打了一个断点,然后开始调试,此时在断点处停下来的状态就是 t,这里是为了和上面进行区分。这里先不细谈。
7、Z (zomble)
比如你早上去晨跑时,突然看到其他跑友躺地上,你虽然救不了人,也破不了案,但是作为一个热心市民,可以先给 120 打电话,再给 110 打电话。随后警察来了,第一时间肯定不会把这个人抬走,清理现场,如果是这样的话凶手肯定会笑开花,第一时间肯定是先确定人是正常死亡还是非正常死亡,如果是非正常死亡,那么立马封锁现场,拉上警戒线,判断是自杀的还是他杀。随后 120 来了,对人的状态进行判断,如果是正常死亡,就判断是因为疾病,还是年纪大了。最终判断出人是是因为疾病离开的,警察和医生的任务已经完成后,不会就把人放这,直接撤了。而是把人抬走,恢复地方秩序,然后通知家属。所以当一个人死亡时,并不是立马把这个人从世界上抹掉,而是分析这个人身上的退出信息,比如说体态特征、血压等信息来确定具体的退出原因。
同样进程退出,一般不是立马让 OS 回收资源,释放进程所有的资源,作为一个死亡的进程,OS 不会说你已经死了,就赶紧把你拉到火葬场,而是 OS 要知道进程是因为什么原因退出的。创建进程的目的是为了完成某件任务,进程退出了,我得知道他把我任务完成的怎么样了,所以 OS 在进程退出时,要搜集进程退出的相关有效数据,并写进自己的 PCB 内,以供 OS 或父进程来进行读取。只有读取成功之后,该进程才算真正死亡,此时我们称该进程为 死亡状态 X
,。其中我们把一个进程退出,但还没有被读取的那个时间点,我们称该进程为 僵尸状态 Z
。
我作为父进程 fork 创建一个子进程,子进程死亡了,但父进程没通过接口让 OS 回收,此时子进程的状态就是 Z。
僵尸状态演示 ❓
这里我们可以写一个监控脚本 while :; do ps ajx | head -1 && ps ajx | grep mytest; sleep 1; echo "####################"; done
来观测:
8、X (dead)
参考 Z 状态。其次 X 状态我们看不到,因为我们释放了,它是一瞬间的。
- 点赞
- 收藏
- 关注作者
评论(0)