13.进程——进程生命周期
上一篇简述了进程的启动过程,这篇来看看进程的生命周期。
在经典的操作系统教材中对于进程的生命周期状态有如下几个:
-
创建 :进程创建成功。
-
就绪 :进程获得了可以运行所需要的各种资源,只要 CPU 就绪就可以运行。
-
运行 :进程运行指令。
-
等待/阻塞 :进程需要等待某些资源,所以被操作系统移出 CPU 进入等待或者阻塞的状态。
-
终止 :进程正常退出或者异常退出。
当进程创建出来后,它处于创建态,当它获取了足够的资源(内存、文件等)后就流转到了就绪态,但此时它还没有进入运行态,因为 CPU 正在忙着其他的进程,还没轮到它运行,当 CPU 有空运行它的指令时,它的状态才流转到运行。如果进程在运行的过程中没有任何阻塞,则它会正常退出;但如果它运行过程中有异常,它会异常退出,这两种退出都属于终止状态。如果进程在运行过程中需要额外的资源,比如读取磁盘信息,我们知道读取磁盘信息是比较慢的,CPU 不能一直等进程完成这个读取的过程,因为 CPU 在这个过程完全可以运行其他进程,所以操作系统会将这个阻塞的进程调度出 CPU,这个进程的状态就流转到了等待/阻塞的状态,当资源获取完成后,它的状态回到了就绪态, 注意:它不能直接回到运行态! 注意上图中箭头的方向。
很多时候理论与实际实现是有一些差距的,比如计算机网络(OSI 七层协议模型),进程状态也是一样。 在 Linux 系统中进程状态不止五种 ,我们来列一下在 linux 中进程都有哪些状态。
-
TASK_RUNNING(简写 R) :在 Linux 中这个状态即可能是正在运行也可能是就绪状态,所以当我们看到这个状态的进程时需要注意,它并不代表正在运行,可能是处于就绪态,不要以为 RUNNING 就是运行态。不知道 Linux 这么设计的用意是什么。
-
TASK_IDLE(简写 I) :空闲状态。当一个进程没有任务需要跑时就会处于这个状态。
-
TASK_INTERRUPTIBLE(简写 S) :可中断的睡眠状态。一般来说这个状态是在等待某些资源的就位,比如等待 socket 连接,一旦这些资源准备好了,进程就会自动离开这个状态。为什么叫做可中断呢?顾名思义,就是我们可以人为的中断它,比如 kill 它。
-
TASK_UNINTERRUPTIBLE(简写 D) :不可中断的睡眠状态。它与上面的 S 状态差不多,都是在等待某些资源,比如 IO 读写,但是它不能被人为中断,我们只能等它自动退出这个状态。很多做底层存储的同学应该会对这个比较熟悉。当进程处于这种状态时研发的同学基本上只能干瞪眼,kill -9 是没有用的,它与僵尸进程的处理方式差不多,如果不满足它的条件进行恢复到 R 状态则需要进行重启。
-
TASK_STOPPED(简写 T) :进程暂停状态。
-
TASK_TRACED(简写 t) :进程追踪状态。当我们进行调试程序时,它就会处于这种状态,使用过 GDB 的同学应该对这个状态比较熟悉。
-
TASK_DEAD-EXIT_ZOMBIE(简写 Z) :僵尸状态。这应该是比较著名的进程状态,应该很少人不知道这个状态吧。这个状态的进程其实已经消亡,只是在 task_struct 里面中对应着的数据结构还没释放。注意:每个进程都会经历僵尸状态。只不过有些进程的父进程因为异常了没有 wait 处理子进程的退出状态导致出现了僵尸状态。正常情况下 ps 或 top 很难捕捉进程的僵尸状态,这个状态太短暂了,但在异常情况下,这个状态的进程又难以清除,基本上只能重启。
-
TASK_DEAD-EXIT_DEAD(简写 X) :销毁状态。进程彻底释放,这个状态比较难捕捉,一般用 top 或者 ps 很少看到这个状态。
如何查看进程的状态呢?这里提供两种方式: top 和 ps 。
上面是 top 命令的截图,关于进行状态的信息主要看红圈中的部分,上面那个红圈是当前系统中进程各种状态的数量统计;下面那个红圈是每个进程的状态。每个状态都可以与上面描述一一对应,可以对照着看。
还可以利用 ps -xf 来看每个进程的状态信息。
欢迎关注公众号:哈扣。