一探Linux下的七大进程状态
本篇博客全站热榜最高排名:6
文章目录 三、Linux下的7种进程状态 4、停止状态T5、进程跟踪状态t6、死亡状态X7、僵死状态Z —— 两个特殊进程 四、总结与提炼
一、前言
Hello,大家好,本文我们所要介绍的是有关Linux下的进程状态
task_ 内容分类
二、操作系统学科下的进程状态
其实那么多的状态,真正主要的也就那么几个,所以接下去我会中重点讲解以下几种进程的状态
1、运行状态
首先我们要谈到的是【运行状态】,这个状态是最普遍的
因为每个进程是需要去竞争CPU资源的,但是呢CPU不可能同时给这么多进程分配资源
提问:一个进程只要把自己放到CPU上开始运行了,是不是一直要到执行完毕,才把自己放下来?
所以呢我们不要拿自己的时间感受去衡量CPU,其运行一遍速度是非常快的,你根本感受不到这种进程切换的效果
2、阻塞状态
在介绍完【运行状态】后,我们再来讲讲【阻塞状态】
上面的这两种状态都可以算作是进程处于阻塞状态
那有同学可能会疑惑这为什么叫做【等待队列】呢?明显只有一个进程鸭
3、挂起状态
最后我们再来讲讲一种状态叫做【挂起状态】
要怎么去省呢?
那有的同学说:为什么要这样去做呢?这样做有什么意义?
看了上面的三种基本的进程状态后我们可以来总结一下,如果要看进程是什么状态的话一般看这个 进程在哪里排队
三、Linux下的7种进程状态
在介绍完操作系统学科下的三种最主要进程状态后,我们对进程的状态有了基本的概念,接下去就让我们正式地来学习一下Linux系统下7种进程状态
先来小结并回顾一下上面所学:
如果当前是【运行状态】,那么接下来就需要被调度运行如果当前是【阻塞状态】,那就等条件就绪,等设备准备好就把当前进程投递到运行队列里,然后再被CPU调度运行如果当前是【挂起状态】,要做的就是把当时换出的代码和数据重新换入,然后再把所对应的进程列入到运行队列中
以下就是关于进程的所有状态
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】
1 #include <stdio.h>2 #include <unistd.h>3 4 int main(void)5 {6 while(1); 7 {8 printf("hello bit\n");9 }10 11 return 0;12 }
1 #include <stdio.h>2 #include <unistd.h>3 4 int main(void)5 {6 while(1); 7 //{8 // printf("hello bit\n");9 //}10 11 return 0;12 }
那有读者就要问了:为什么把打印语句给去掉之后就变成这样了呢?
这里再补充说明一下这个S和R后面的+
不过呢,R状态并不代表这个进程就在运行,而代表其在运行队列中排队而已
2、浅度睡眠状态S
接下去我们再来介绍一下Linux下的睡眠状态S
1 #include <stdio.h>2 #include <unistd.h>3 4 int main(void)5 {6 while(1)7 {8 sleep(1); 9 printf("hello bit\n");10 }11 12 return 0;13 }
那有同学就很疑惑,这个进程不是在运行吗?为什么不是R状态呢?
1 #include <stdio.h>2 #include <unistd.h>3 4 int main(void)5 {6 int a = 0;7 printf("Enter# ");8 scanf("%d", &a);9 10 printf("echo : %d\n", a);11 return 0; 12 }
3、深度睡眠状态D
除了【浅度睡眠】之外呢,还有一种叫做【深度睡眠】,它们俩呢,都是 阻塞状态
好,接下去呢我就通过一个故事来描述一下这个【深度睡眠】到底是怎样一种状态
所以呢,同学们,我们要明白这么一个道理:操作系统认为当前系统能行的话就直接让用户去用就可以了,如果扛不住了就置换页表,实在不行了就去会杀进程
一场有趣的官司
那因为随着这份重要数据的丢失呢,就引发了一场官司
以下呢,是三个人的辩词
【操作系统】:
法官⚖️听了这番说辞后心里想了想,确实是。于是呢这个时候便把茅头指向了丢掉数据的磁盘✒ 发问道:你为什么要丢数据呢?
【磁盘】:
操作系统一听:诶,这货说的好像确实没什么问题。那就就把视角转向了受害人即【进程】这一方。反正操作系统没错、磁盘没错,那就是你的问题喽!
【进程】:
那这个时候法官一想,它们三个说的似乎都挺有道理,难道是我错了吗?
那我们在上面有提到过处于【浅度睡眠】的进程,是可以被kill掉的,那么我们就要让这个进程的状态变为【深度睡眠】才对,即[D]
那这个时候就又有同学问了:D状态这么强大吗,那如果一个操作系统里有很多的D状态,这怎么办呢?
不过呢这个[D]就没办法在这里给读者演示了,因为D状态的进程只有处于高IO的情况才可以演示。有兴趣的可以去研究一下Linux下的命令dd
4、停止状态T
好,接下去呢我们来讲讲【停止状态T】
kill -l
kill -19 PID
kill -18 PID
所以呢,如果我们要将一个进程给终止的话,发送19号信号即可,要让其继续启动起来,则发起18号信号
那我现在要问了,这个T停止状态和S睡眠状态有什么不同呢?
状态进程 完全暂停了, 其不会再接收任何信号了一个进程通过状态可以控制另一个S和D一定是在等待某种资源,而T状态可能在等待某种资源,也可能被其他进程控制 5、进程跟踪状态t
接下去呢,我们再来说说进程的跟踪状态t,还记得我们在基础篇中所学习的 GDB调试 吗?
6、死亡状态X
对于【死亡状态X】来说呢,这个状态只是一个返回状态,你不会在任务列表里看到这个状态
第一种方法就是向这个进程发送9号信号,就可以杀掉这个进程
kill -9 PID
第二种方法就是通过这个进程的名称来杀掉它
killall 进程名
7、僵死状态Z —— 两个特殊进程
接下去我们来介绍一种状态叫做【僵死状态Z】,对于这个状态,我们要涉及到两个特殊的进程叫做 僵尸进程 与 孤儿进程
不过在讲这个僵死状态前,我们先来看看 0这个东西
这里我们写几句代码来测试一下
36 int ret = 20; 37 if(ret == 20) return 0;38 else return 3;
① 僵尸进程
首先我们要来介绍的是僵尸进程,这里呢通过一个故事来进行引入
好,我们回归正题,来说说这个【僵尸进程】
那我现在想问了:有一个进程暂时退出了,它要将它的状态暂时维持一段时间,问题是它维持给谁看呢?
就上面这样生冷的文字来叙述还不太行,接下去我们通过实际的案例来观察一下
1 #include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 5 int main(void)6 {7 pid_t id = fork();8 if(id == 0)9 {10 // child11 int cnt = 5;12 while(cnt)13 {14 printf("I am child, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt);15 sleep(1);16 17 cnt--;18 } 19 exit(0);20 }21 else22 {23 // father 24 while(1)25 {26 printf("I am father, pid: %d, ppid: %d\n", getpid(), getppid());27 sleep(1);28 }29 }30 return 0;31 }
所以我们总结一下:
进程一般退出的时候,一般其不会立即彻底退出。如果父进程没有主动回收子进程信息,子进程会一直让自己处于Z状态,这也是为了方便后续父进程读取子进程的相关退出结果。
那对于上面的这种子进程,我们就将其称作为是【僵尸进程】,不过呢这种进程是存在一定危害的!
② 孤儿进程
那此时我想问:这个父进程突然之间退出了,但是呢它的父进程并不知晓,那为何这个父进程没有处于【僵尸状态Z】呢?
接下去我们来将上面测试僵尸进程的代码做个修改,让父进程先于子进程退出
1 #include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 5 int main(void)6 {7 pid_t id = fork();8 if(id == 0)9 {10 // child11 int cnt = 500;12 while(cnt)13 {14 printf("I am child, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt);15 sleep(1);16 17 cnt--;18 }19 exit(0);20 }21 else22 {23 int cnt = 5;24 // father 25 while(cnt--) 26 {27 printf("I am father, pid: %d, ppid: %d\n", getpid(), getppid());28 sleep(1);29 }30 }31 return 0;32 }
ps ajx | head -1 && ps ajx | grep systemd
那为何会出现上面这种现象呢?是这个子进程突然换父进程了吗?
但是这个孤儿进程为什么要被领养呢?
那其实我们就可以解释上面的事情了
四、总结与提炼
最后来总结一下本文所学习的内容
接下去我们又介绍了在Linux系统下的七种进程状态,分别是:运行状态R、浅度睡眠状态S、深度睡眠状态D、停止状态T、进程跟踪状态t、死亡状态X、僵死状态Z