Bootstrap

Linux-进程的状态详解

目录

回顾

进程的状态

1."R"状态

 1."S"状态

3.“D”状态

4.“T”状态

“+”的意义

5.“t”状态

6.“X”状态

7.“Z”状态

8.孤儿进程

总结


回顾

上篇文章Linux-进程的介绍和标示符,讲了进程是由进程控制模块(PCB)、它的代码和数据构成的,而在Linux中进程的PCB就是一个名叫task_struct的结构体,里面存放着进程的数据和状态,操作系统如果要对进程进行操控,是对PCB进行管理,而不是对进程代码数据直接管理。其中我们上篇文章详细讲了PCB存放的标示符(PID)和它的父进程标示符(PPID)。

而这篇文章,我们详细讲解一下进程的状态。

进程的状态

我们先来看看Linux的内核源码对于进程的状态的分类是怎么样的

/*
* 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"状态

R(running),顾名思义,就是运行状态,一个程序在cpu中被跑的时候,就是运行状态。

这里我们提出一个疑问,我们打开一个app,打开一个播放器,打开qq,打开网页,我们随时可以对这些程序进行操作,是不是代表着这些进程无时无刻处于运行状态呢?       不是的

一般我们的电脑都只带了一个cpu,可是,有那么多进程,cpu是怎么“同时运行”那么多进程的呢?

如果说cpu是运行完一个进程再继续运行下一个进程,就会导致一个进程可能会长时间占用我们的cpu,而导致其他进程没有享受到cpu的资源。所以cpu是通过一个运行队列来完成“同时运行”多个进程的。

而这里就又提出了一个时间片的概念,一个进程在队列的一个轮回中被运行的时间。

一个进程运行了对应的时间片时间,立马就到队列尾部,而后一个进程就再被cpu运行对应的时间片时间,以此反复,从而达到“同时运行”的效果,而这个“同时运行“并不是真正的同时运行,只是我们肉眼看到的“同时运行”,因为周期很快所以我们感受不到。

而一个程序对应的时间片也是存放在PCB中,影响进程对应的时间片时间是一个进程的优先级,我们后面会讲。

我们写一串代码感受一下

看右边我们的进程有一个R+的状态,这就说明它是在运行中。 

 1."S"状态

 R(sleeping),睡眠状态,说明当前程序不在运行队列,可能是因为某些设定或者在等待某些硬件的输入输出。

跟R状态一样,它也有一个队列,名为rest_queue

 我们直接来感受一下

让这个程序每隔一秒运行一次。

这里我们就能看到程序大部分时间是处于S状态,程序在R状态存在的时间太短暂了!! 

这种情况就是程序因为设定,会从运行队列移动到等待队列中。

而另一种情况

 

让这个程序不间断的打印内容。是不是会一直处于运行状态呢?

 

 

 我们连续多次查看进程状态,发现这个进程大部分时间是处于“S”状态的,只有一小部分时候处于“R”状态,这是为什么呢?我们明明看到程序一直在打印刷屏。

这是因为我们的输入输出设备比较慢,而我们的cpu更快,我们的程序已经准备就绪了,可是还需要等待输入输出设备的响应,这就导致了我们的进程进入等待队列中等待输入输出设备的响应,这就是第二种情况。

3.“D”状态

D磁盘休眠状态(disk sleep)  称为深度睡眠状态,不可中断睡眠状态。

如果一个进程长时间没有等到对应的数据触发运行条件,操作系统会认为这个进程是一个垃圾进程,会把这个进程杀掉,可是,有的时候一个程序就是需要等那么久,又怕被操作系统误杀,那怎么办,这时候进程就有一种特殊的睡眠状态,就是不让操作系统随便把进程杀掉,等到IO数据全部准备就绪再运行,这就叫做深度睡眠也叫不可中断睡眠。

4.“T”状态

T停止状态(stopped)可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

这个状态与休眠,状态有一定区别,进程即使处于S状态,它里面的PCB数据也有可能会因为其他原因发生改变,但是停止状态真的是停止了,并且如果我们要想让一个程序进入T状态,就必须通过发送SIGSTOP信号。

我们使用 kill -l 命令来查看有几种信号模式

kill -9 命令是发送杀死进程的信号

kill -19 命令是发送停止进程的信号

kill -18 命令是发送进程继续的信号

我们使用刚刚的死循环程序,让他一直跑下去

进程停止后,我们再查看进程的状态

 

 这时他就处于“T”状态,不知道大家是否发现没有,之前我们查看进程的状态都有“R+”,“S+”,

可是这里的“T”没有“+”,这是什么意思?

“+”的意义

如果一个进程的状态后面有+,说明这个进程是在前台运行的,什么是前台运行?就比如我们可以通过ctrl + c 中断程序,但是如果是后台运行,我们就不能通过这种ctrl+c的方式中断程序,并且后台打印的内容不影响我们在前台输入指令。

这里我们紧接上面的已经处于“T”状态的进程,如果要让他继续跑起来使用 kill -18 [进程PID]

让他重新跑起来之后,进程的状态也变成的没有+,并且我没办法中断程序,那么我又应该怎么然他停下来?

使用kill -9 [进程PID]命令

 程序终于停下来了

5.“t”状态

"t (tracing stop)", 可以称为调试停止状态

我们在调试程序的时候就是处于这种状态

我们使用gdb进入调试

6.“X”状态

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态
例如一个程序跑完了,会返回一个值。

7.“Z”状态

 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。

举个例子

这个程序,子进程会很快走完,父进程会一直走下去,子进程的返回值本应该给父进程,但是如果父进程没有走完,子进程已经走完了,子进程的返回值就谁都给不了,就会处于僵尸状态。

注意:如果一个进程处于僵尸状态,那么这个进程将无法被杀死,即使使用kill -9也无济于事,这就可能会导致一个问题——内存泄漏。

 这就是“Z”僵尸状态。

8.孤儿进程

那假如子进程走完之后,父进程已经跑完了,或者是被杀掉了,该怎么办?

 

 父进程只打印一次并让他休眠10s,子进程一直在运行。

我们会看到,当父进程跑完之后,子进程的PPID变成了1,而PID为1的进程就是我们的操作系统,所以,可以得出结论,如果父进程跑完了,子进程还在跑,子进程就会变成孤儿进程,被操作系统接手,并且运行状态变成了后台运行。

总结

以上我们就详细的介绍了进程的所有的状态,而进程的状态信息都是储存在进程的PCB中,操作系统通过从PCB查看进程的状态来分配进程。

;