目录
Linux进程的各种状态的表示:
R状态的测验:
S状态的测验:
T状态的测验:
这次讲解一个新指令:kill -l
t状态测验:追踪暂停
X状态:死亡状态
Z状态:僵尸状态
进程一直处于僵尸状态的危害:
孤儿进程:
最后简单来说一说状态后面有+号的意思:
在上一篇博客中,我介绍了宏观层面下普遍的操作系统对于进程多种状态的理解,有运行状态、阻塞状态、挂起状态,感兴趣的同学可以看看:操作系统层面下——进程状态讲解
而在Linux操作系统中,进程的状态又是怎样的呢?
Linux进程的各种状态的表示:
从上图可知,Linux操作系统中公有7种类型的进程状态:
其中R状态是运行状态;
S是阻塞状态;
T是暂停状态(浅度睡眠),它其实也算是阻塞状态的一种分支;
D算是深度睡眠状态;
X是死亡状态;
Z是僵尸状态;
t是追踪暂停状态
R状态的测验:
通过查看该进程的状态信息可知,它为R+,R从上面可知为运行状态,这里卖个关子,对于状态后面的加号,一会进行讲解。
S状态的测验:
该代码相比较于试验1的代码多了一个printf函数调用。
运行程序后:
通过右图发现,该程序的状态变成了S+,从开头的状态表示可知,S状态是阻塞状态。为什么进程会变成阻塞状态呢?它不是运行的好好的吗?
之前讲到进程转换成阻塞状态一定是因为该进程在被CPU执行的过程中,需要申请硬件资源,导致CPU终止了该进程的执行,操作系统将其调入硬件处理器的等待队列中等待着硬件资源的处理。
这个例子也是如此,因为printf函数是需要将运算结果输出到显示屏的,它是关联到硬件的显示屏的,所以会申请硬件资源,程序运行虽然是一瞬间的事情,但在此运行中大部分时间都在使用硬件资源,那么该进程就会从运行状态转到阻塞状态。
T状态的测验:
仍是与例二一样的代码。
运行该程序 :
这次讲解一个新指令:kill -l
功能:kill指令 可将指定的信号(singnal)送至程序。预设的信息为 SIGTERM(15),可将指定程序终止。
共有60多种信号,各有各的作用去终止进程运行。
11290是该进程的Pid编号,想要终止一个进程,直接使用指令:kiil -[所选信号] [进程pid编号]。
根据ps ajx指令查看该进程的状态信息变成了T状态:
因为19号信号的作用是使得正在运行的进程暂停。
所以触发进程暂停为T状态的直接原因是对该进程使用SIGSTOP信号。
t状态测验:追踪暂停
例:
源代码:
使用gcc编译器生成Debug版本可执行文件:
开始使用n或s指令开始调试已启动的程序:
通过监视器查看该进程状态信息:
红色框中涉及了多条指令:
1.while : ;do [输入想要输入的指令]; done :该指令作用是一直做死循环
2.ps ajx | head -1 :显示所有进程状态信息并且显示检测器的属性栏
3.ps ajx | grep hahha :显示文件名为hahha进程的状态信息
4.grep -v grep :反向查找不含有grep关键字的信息
5.sleep num :休眠num秒种
绿框内容表示:使用gdb调试器运行上面生成的可执行文件代码。在框里面看有一个进程在运行,即gdb hahha,它处于阻塞状态。
当我开始给程序打上断点,并开始使用指令run后,进程状态检测器检查到hahha处于t状态,如上图橙色框中的内容,说明了该进程现在正在处于被追踪暂停状态。
也就是说触发某个进程状态为t状态的只能是使用gdb调试器对该进程进行断点调试才行。
X状态:死亡状态
该状态表明了进程退出后的一种状态,我们在操作系统的进程状态监测中也无法看到,因为进程退出的一瞬间会从某个状态转换为Z状态,然后一瞬间就会被父进程给回收掉。
Z状态:僵尸状态
1.什么是僵尸进程?
在Linux系统中,正常情况下,子进程是通过父进程创建的,且两者的运行是相互独立的,父进程永远无法预测子进程到底什么时候次啊会结束运行,当子进程某个命令结束自己的生命时,其实它并没有真正的被销毁,内核操作系统只是释放了该进程所占有的所有资源(打开的文件,占用的内存等),,但是一定会保留该进程的PCB,因为PCB中的进程状态显示栏不能直接显示为死亡状态X,只有当父进程通过使用特定的函数将子进程的信息全部回收掉后,处理完后事,OS才会真正将子进程的所有信息全部释放掉。这样设计的目的主要是:父进程需要知道子进程到底什么时候才结束所定的一个闹钟,子进程一退出,父进程身旁的闹钟就会响,意味着它知道了子进程退出了,该去给子进程处理后事了。
举个例子:小明早上六点起床去公园跑步,在他视野的前方,同样也有一个老人在跑步,这时老人突发心脏病倒在了地上,小明发现后快步跑到前方查看老人的情况,发现老人没了呼吸,赶紧拨打了110和120。等几分钟过后,警察和医生飞速奔来检查和救治老人,但抢救无效老人已经去世了。医生将老人送至医院后联系其家属进行后事处理,警察则在现场拉起了警戒线,收集老人死亡前后的所有原因和线索。而老人在突发心脏病离世到医生和警察为其处理的过程在Linux下就叫做僵尸状态。
所以只要子进程退出,父进程还在运行,但是父进程一直没有回收子进程的资源和退出信息,那么子进程就一直处于僵尸状态。
例:
生成可执行文件,并允许:
通过ps ajx 指令循环查看父子进程状态:
由上图可知:蓝框为父进程,红框为子进程(此时子进程已经结束退出),父进程还未回收处理,子进程状态为Z装,且后面显示<defunct>。
虽然mytest该进程的父进程还在执行,但其子进程已经成为僵尸进程了,且以终止状态出现在状态表中,可见defunct一一失效的意思,即子进程成为了失效的进程,虽然它仍在运行着,但是是行尸走肉,所以叫做僵尸,它只能默默等待着父进程结束退出,让父进程来回收自己,结束生命!
进程一直处于僵尸状态的危害:
进程的退出状态就会一直被维持下去,它要告诉父进程“你交给我的任务,我办的怎么怎么样了......"。如果父进程一直不读取,那么子进程就一直处于Z状态。
维护退出状态本身就是用资源做维护,也属于进程的基本信息,保存在PCB中,换句话说,Z状态一直不退出,PCB一直就要维护。
一个父进程创建了很多个子进程,若是它们都退出了父进程不回收,就会造成内存资源的浪费!即内存泄漏。
说完了僵尸进程,就不得不提一提孤儿进程了,造成孤儿进程的原因与造成僵尸进程的原因正好是的相反的。
孤儿进程:
在上边将了子进程如果提前退出,该进程成为僵尸进程。
若是父进程先退出,子进程仍在运行,那么子进程就称之为”孤儿进程“。
父进程先退出的话,我们不需要输入特定的函数或者指令去回收父进程的退出信息,因为bash进程会自己做这些事情,不劳烦我们用户操心!
bash进程上上篇博客提到过,bash是一切父进程的父亲——老祖宗,就连我们输入的指令都是由bash的子进程去执行的,所以父进程退出,它由bash去进行善后处理。
此时,父进程被bash回收后,只剩下子进程一个人孤零零的在运行着程序,这时子进程的ppid会自动变成1(bash的pid编号默认就为1),也就相当于是bash进程代替了原来的父进程,给这个子进程当父亲。那操作系统为什么要这么干?
如果bash不领养子进程,等到子进程退出的时候会成为僵尸进程,僵尸进程原本是父进程会进行回收处理,但父进程已经挂掉了,无人收尸便会造成内存泄漏,所以需要bash去领养!子进程退出后,就由bash对该进程进行回收,名正言顺。
例:
针对父进程执行流采用exit命令退出,子进程仍处于while循环中执行代码。
运行结果:
最后简单来说一说状态后面有+号的意思:
状态后面有+号表明该进程现在是前台运行方式,我们可以使用ctrl+c,ctrl+z,ctrl+\快捷键使其终止。
而状态后面没有+号表明进程是后台运行方式,使用上面的快捷键无法使进程停止,只能使用kill -9强制终止!