目录
[可中断睡眠 S (sleeping)](#可中断睡眠 S (sleeping))
[不可中断睡眠 D (Disksleep)](#不可中断睡眠 D (Disksleep))
[运行状态 R (running)](#运行状态 R (running))
[停止状态 T (stopped)](#停止状态 T (stopped))
[跟踪停止状态 t (tracing stop)](#跟踪停止状态 t (tracing stop))
[僵尸状态 Z (zombie)](#僵尸状态 Z (zombie))
[孤儿状态(orphaned state)](#孤儿状态(orphaned state))
进程状态
理论:

状态 | 描述 |
---|---|
新建状态 | 进程刚被创建,尚未进入就绪队列。 |
就绪状态 | 进程已准备好执行,等待 CPU 调度。 |
执行状态 | 进程正在 CPU 上执行指令。 |
阻塞状态 | 进程等待某事件(如 I/O 完成),无法执行。 |
挂起状态 | 进程被从内存中移出,暂时停止执行。 |
终止状态 | 进程执行完毕或异常终止,资源被回收。 |
状态转换路径 | 转换说明 |
---|---|
新建状态 → 就绪状态 | 当进程被创建完成后,会被提交到就绪队列,进入就绪状态。 |
就绪状态 → 执行状态 | 调度程序根据一定的调度算法,从就绪队列中选择一个进程,将 CPU 分配给它,使其进入执行状态。 |
执行状态 → 就绪状态 | 如果进程的时间片用完,或者有更高优先级的进程进入就绪队列,当前进程会被剥夺 CPU,重新回到就绪状态。 |
执行状态 → 阻塞状态 | 当进程在执行过程中需要等待某个事件(如 I/O 操作)时,它会主动放弃 CPU,进入阻塞状态。 |
阻塞状态 → 就绪状态 | 当进程等待的事件发生时(如 I/O 操作完成),它会被唤醒,从阻塞状态回到就绪状态,等待再次被调度执行。 |
执行状态 → 终止状态 | 当进程完成了所有的执行任务,或者因为异常情况被终止时,会进入终止状态,操作系统会回收其资源。 |
就绪状态 ↔ 挂起状态 | 当内存充足时,挂起的就绪进程会被唤醒进入就绪状态;当内存不足时,部分就绪进程会被挂起以释放内存。 |
阻塞状态 ↔ 挂起状态 | 当内存充足时,挂起的阻塞进程会被唤醒进入阻塞状态;当内存不足时,部分阻塞进程会被挂起以释放内存。 |
执行状态:
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

阻塞状态:

挂起状态:

进程切换:
进程在切换,最重要的一件事情是:上下文数据的保护和恢复.
CPU 内的寄存器:
寄存器本身是硬件,具有数据的存储能力,CPU 的寄存器硬件只有一套!!
CPU 内部的数据,可以有多套,有几个进程,就有几套和该进程对应的上下文数据.
寄存器!= 寄存器的内容CPU 内部的所有的寄存器中的临时数据,叫做进程的上下文

我们经常写的函数代码
int add(int a, int b)
{
int c = a + b;
return c;
}
int ret = add(10, 20)
结果就是通过寄存器返回的
实际:
之前介绍过task_ struct内容
信息类别 | 具体内容 |
---|---|
标识符 | 描述本进程的唯一标识符,用来区别其他进程。 |
状态 | 任务状态,退出代码,退出信号等。 |
优先级 | 相对于其他进程的优先级。 |
程序计数器 | 程序中即将被执行的下一条指令的地址。 |
内存指针 | 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。 |
上下文数据 | 进程执行时处理器的寄存器中的数据。 |
I/O 状态信息 | 包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。 |
记账信息 | 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。 |
其他信息 | 进程间通信相关参数、资源限制设置、亲缘关系、安全上下文、调度策略与参数以及链接信息等内容 |
进程状态:表示进程要么正在 CPU 上执行指令,要么已经准备好被 CPU 调度执行,处于就绪队列中等待获取 CPU 资源。
linux-6.16内核源码


为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。
下面的状态在kernel源代码里定义:
static const char * const task_state_array[] = {
"R (running)", /* 0 */ #define TASK_RUNNING 0x00000000
"S (sleeping)", /* 1 */ #define TASK_INTERRUPTIBLE 0x00000001
"D (disk sleep)", /* 2 */ #define TASK_UNINTERRUPTIBLE 0x00000002
"T (stopped)", /* 4 */ #define __TASK_STOPPED 0x00000004
"t (tracing stop)", /* 8 */ #define __TASK_TRACED 0x00000008
"X (dead)", /* 16 */ #define EXIT_DEAD 0x00000010
"Z (zombie)", /* 32 */ #define EXIT_ZOMBIE 0x00000020
};
状态标识 | 状态名称 | 状态描述 |
---|---|---|
R (running) | 运行状态 | 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里 |
S (sleeping) | 睡眠状态 | 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep)) |
D (Disk sleep) | 磁盘休眠状态 | 有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待 IO 的结束 |
T (stopped) | 停止状态 | 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行 |
t (tracing stop) | 跟踪停止状态 | 进程被调试器(如 gdb)附加并暂停,用于跟踪调试 |
X (dead) | 死亡状态 | 这个状态只是一个返回状态,你不会在任务列表里看到这个状态 |
Z (zombie) | 僵尸状态 | 当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码 |
写个简单的代码,进行逐一理解:
bash
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
while(1)
{
printf("I am a process! pid:%d\n",getpid());
sleep(1);
}
}
睡眠状态
在 Linux 中,进程的睡眠状态(对应状态标识 S,即 "S(sleeping)"、 D,即 " D(Disksleep)")他们本质都是在等待进程资源就绪。
对比维度 | 可中断睡眠(S 状态) | 不可中断睡眠(D 状态) |
---|---|---|
信号响应 | 可被外部信号(如 SIGINT )中断 |
不响应任何外部信号(包括 SIGKILL ) |
适用场景 | 等待用户输入、网络数据等非关键事件 | 等待磁盘读写、硬件 I/O 等关键操作 |
唤醒条件 | 事件完成 或 收到信号 | 仅当 I/O 操作完成 |
数据安全性 | 中断无风险 | 强制中断可能导致数据丢失或硬件错误 |
可中断睡眠 S (sleeping)
写一个简单的shell脚本监控进程:
bash
while :; do ps axj|head -1 && ps axj|grep process|grep -v grep ;sleep 1;done
每隔 1 秒显示一次包含 "process" 名称的进程信息(含标题行),不显示grep 本身进程。
结果如图

STAT总是S+ (睡眠状态) ,可是我们的程序一直在运行,为什么是睡眠状态呢?
S
:表示进程处于睡眠状态(可中断睡眠),即进程正在等待某个事件(如 I/O 完成、信号等)。- +:表示该进程属于前台进程组,通常是当前终端中正在交互的进程。
可以用符号**&**用于将命令放到后台执行

之前我们介绍过冯诺依曼和CPU运行速度:


显示器属于输出设备,是外设。他需要从内存中读取数据后刷新 。
而CPU 运行的速度极快,CPU快速将数据写入到内存当中,并等待显示器就绪后刷新到显示器中,所以大部分时间都是在等待显示器资源就绪,我们就看见大部分时间进程都在等待。

进程处于休眠状态,但是可以被外部事件如Ctrl +C 打断时,叫做Linux 可中断睡眠 。
不可中断睡眠 D (Disksleep)
因为电脑设备问题,不具体演示D状态。只做介绍:
不可中断睡眠也被称为不可中断休眠状态,是指进程正在等待某些特定的、关键的硬件资源操作完成,在此期间,进程不会响应除系统断电、硬件故障等极端情况外的任何外部信号(包括常用的SIGKILL 等强制终止信号),只有当等待的事件(通常是 I/O 操作)结束后,进程才会被唤醒,脱离该状态。
进入该状态的场景
- 磁盘 I/O 操作:当进程需要从磁盘读取数据或者向磁盘写入数据时,可能会进入不可中断睡眠状态。比如一个数据库程序执行磁盘上数据文件的读写操作,在等待磁盘控制器完成数据传输的过程中,进程就会处于 D 状态。这是为了确保数据读写的原子性和完整性,避免在数据传输过程中因进程被中断而导致数据错误或丢失。
- 其他硬件设备交互:除磁盘外,与其他外部硬件设备(如 USB 设备、打印机、网络设备等)进行数据交互时,若进程需要等待设备响应或操作完成,也可能进入不可中断睡眠。例如,当进程向打印机发送打印任务后,等待打印机确认接收并开始打印的过程中,可能处于不可中断睡眠状态。

解决办法:
1.重启--断电
2.等待进程自己醒来
运行状态 R (running)
在 Linux 中,进程的运行状态(对应状态标识 R,即 "R (running)")是指进程处于可被 CPU 调度执行的状态,具体包含两种情况:
- 正在运行中:进程当前正在占用 CPU 资源,执行指令。
- 处于运行队列:进程已准备好执行,但暂时未获得 CPU 时间(因系统中存在多个就绪进程,需等待调度器分配 CPU 资源)。
当我们把之前的代码取消 printf 让 CPU 不与显示器打交道时:


我们可以看见进程一直处于运行状态。
停止状态
在 Linux 中,进程的停止状态(对应状态标识 T,即 "T(stopped**)"、** t,即 " t(tracing stop**)"**)他们本质是进程暂停,等待进一步唤醒。
状态标识 | 状态名称 | 状态描述 |
---|---|---|
T (stopped) | 停止状态 | 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行 |
t (tracing stop) | 跟踪停止状态 | 进程被调试器(如 gdb)附加并暂停,用于跟踪调试 |
停止状态 T (stopped)
我们先来了解两个信号
|-----------------|--------------------------------------|
| SIGCONT(18) | 用于继续被暂停的进程,与 SIGSTOP 或 SIGTSTP 配合使用。 |
| SIGSTOP(19) | 暂停进程,不能被进程捕获。 |

然后就可以暂停和开始了:

跟踪停止状态 t (tracing stop)
跟踪停止状态:进程被调试器(如 gdb)附加并暂停,用于跟踪调试
我就用之前gdb写的代码来测试:

僵尸状态 Z (zombie)
**僵尸状态(Zombies)**是一个比较特殊的状态。当进程退出并且父进程(使用 wait () 系统调用)没有读取到子进程退出的返回代码时,就会产生僵尸进程。
僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程就会进入僵尸状态(Z 状态)。
之前我们说 进程=内核数据结构task_struct +代码 +数据
部分代码和数据可以释放,但是task_struct 要保留给父进程读取退出状态,如果父进程一直不读取,就会造成内存泄漏。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid=fork();
if(pid==0)
{
int cnt=5;
while(cnt)
{
printf("I am Child pid:%d cnt=%d\n",getpid(),cnt);
sleep(1);
cnt--;
}
}
else
{
while(1)
{
printf("I am parent pid=%d \n",getpid());
sleep(1);
}
}
return 0;
}

死亡状态X(dead)
X(死亡状态)是进程生命周期的终点,代表进程彻底执行完毕且资源正被操作系统释放,因持续时间极短,无法在任务列表中观测到,因此不做演示。
孤儿状态**(orphaned state)**
当父进程先于子进程终止时,子进程就会进入孤儿状态(orphaned state),随后被系统的初始化进程(如 init 或 systemd)接管,由其负责最终的资源回收。

总结
