进程的状态信息存储在进程的task_struct(PCB)中。
进程状态的意义是方便操作系统快速的判断进程,完成特定的功能,比如调度,其本质是一种分类。
下面是Linux内核源码对状态的定义 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
};
R.运行状态
当进程要运行就需要把进程加载到CPU中,而计算机的CPU资源是有限的,进程可能有很多,所以进程可能会等待CPU资源,拿我们就需要一个队列来管理在等待CPU资源的进程,这个队列叫做运行队列。在运行队列中等待的进程所处的状态就是运行状态。
所以当一个进程处于运行状态时并不代表该进程就在占用CPU资源,只是当前进程被放在了运行队列中,随时可供CPU调度。
演示代码
while(true)
{
std<<cout"I am a process"<<std::endl;
}
让一个进程不断的打印一句话,其现象为:
一种在运行的程序,按理说应该是R状态,但起始它大部分时间都是S状态,因为显示器的速度比较慢,所以在打印的时候可能会进入等待状态,所以一般大部分时候都是S状态,少部分是R状态。
这里状态后面带的+号表示进程是在前台运行的,不带+号则表示在后台运行,假设我的程序名叫做myproc。
./myproc(直接在当前目录下运行,是前台进程,运行时可以输入命令,也就可以用ctrl+c杀掉该进程)
./myproc&(在运行命令后面加&,是后台进程,无法输入命令,也就不能用ctrl+c杀掉进程,只能向进程发送9号信号杀掉进程)
S.睡眠状态/D.磁盘休眠状态
进程并不是只会等待CPU资源,当进程想要完成某种任务时,可能会出现任务条件不具备的情况,那这时进程就需要等待这些其他资源就绪,就会进入S或D状态,与运行状态类似,等待的进程也需要一个队列对其进行管理,进程等待CPU资源时叫做运行队列,等待其他资源时就叫做等待队列。
进程在运行时,有可能因为运行的需要,会处在不同的队列里,而在不同的队列所处的状态就是不一样的,这也就是状态本质是一种分类的体现。
我们把进程从运行队列中放到等待队列中的过程叫做挂起等待(阻塞),从等待队列放到运行队列的过程叫做被CPU调度或唤醒进程。
S状态与D状态的区别:
S状态也叫可中断睡眠,是浅度睡眠
D状态也叫不可中断睡眠,是深度睡眠
进程如果处于D状态,那么这个进程就不能被kill掉,因为它不再响应异步信号。想要干掉这个进程,只能等进程完成或者电脑重启。
T.暂停状态
进程处于暂停状态,此时信息没有任何更新,是完全的暂停。与S状态的区别是S状态还会有一些数据更新,比如睡眠了多少秒等。
可以用命令kill -l查看信号
18号信号让进程变成T状态,可以用命令(kill -18 “进程的PID”)向进程发送该信号。
19号命令让进程从T状态恢复,可以用命令(kill -19 “进程的PID”)向进程发送该信号
通过向进程发送18号信号,让进程进入了T状态,发送19号信号,进程又回到了R,S状态,但是这时候的进程状态后面没有+号,代表是后台进程,所以只能向进程发送9号信号杀掉进程。
t.追踪状态
也是一种暂停,是我们控制进程一步一步的执行,就像我们的调试过程。
X.死亡状态
CPU会回收进程的资源,包括基础相关的内核数据结构(PCB)+代码和数据,相当于进程彻底的没了。
Z.僵尸状态
在进程死亡时,其父进程会对其进行资源回收,如果没有进行资源回收的进程退出就会进入Z状态,这时的进程就叫做僵尸进程。
下面是代码演示
#include <iostream>
#include <unistd.h>
int main()
{
pid_t id=fork();
if(id==0)//子进程
{
while(true)
{
std::cout<<"child is running"<<std::endl;
sleep(1);
}
}
else if(id>0)//父进程
{
std<<cout<<"parent is running"<<std::endl;
sleep(20);
}
return 0;
}
我们可以用上面的进程检测脚本检测我们的进程。
让父进程运行20秒,子进程不断的运行,这时候我们把子进程kill掉,可以发现子进程的状态变成了Z,因为父进程还没有运行结束,子进程被kill了,就没有回收它的资源,所以变成了僵尸进程。
如果我们让这个代码一种运行下去,20秒后子进程还没有结束它的父进程就已经结束了,那么这个子进程会被1号进程(也就是操作系统)领养,叫做孤儿进程
总结
当进程开始运行,首先会对进程进程初始化,当初始化完成时进程就会进入就绪状态,在运行队列中等待CPU的调度,当时间片来了进程就被加载到CPU中运行,这时的进程属于运行态,时间片到了进程就再次被放入运行队列,回到就绪态,运行态和就绪态加起来属于R状态。
进程在R状态时可能会因为信号或者事件而需要进行等待,这时的进程就属于挂起等待或者阻塞,其状态可能是S,D,T中的一种,当等待结束后,进程又会回到R状态中的就绪态开始执行。
当程序运行完成结束时,进程就会进入Z,X状态,直到资源被回收,运行完毕。