目录
[二、Linux 内核的进程状态(内核源码定义)](#二、Linux 内核的进程状态(内核源码定义))
[1. R 运行状态(TASK_RUNNING)](#1. R 运行状态(TASK_RUNNING))
[2. S 睡眠状态(TASK_INTERRUPTIBLE)可中断睡眠](#2. S 睡眠状态(TASK_INTERRUPTIBLE)可中断睡眠)
[3. D 深度睡眠(TASK_UNINTERRUPTIBLE)不可中断睡眠](#3. D 深度睡眠(TASK_UNINTERRUPTIBLE)不可中断睡眠)
[4. T 停止状态(TASK_STOPPED)](#4. T 停止状态(TASK_STOPPED))
[5. Z 僵尸状态(TASK_ZOMBIE)【重中之重】](#5. Z 僵尸状态(TASK_ZOMBIE)【重中之重】)
[6. X 死亡状态(TASK_DEAD)](#6. X 死亡状态(TASK_DEAD))
[1. 进程的独立性](#1. 进程的独立性)
[2. 进程组 & 会话](#2. 进程组 & 会话)
[Q1:R 状态代表进程一定正在 CPU 上运行吗?](#Q1:R 状态代表进程一定正在 CPU 上运行吗?)
[Q2:D 状态进程 kill -9 能否杀掉?](#Q2:D 状态进程 kill -9 能否杀掉?)
[Q5:nice 值的范围和作用?](#Q5:nice 值的范围和作用?)
一、回顾:PCB(task_struct)
Linux 下每一个进程都有一个 PCB,结构体task_struct,里面包含大量描述进程属性信息:
- 进程 id:pid
- 内存描述:虚拟地址空间信息
- 寄存器上下文(进程切换时保存的硬件上下文)
- 文件描述符表
- 进程状态 state(本文核心成员)
- 优先级、调度相关属性
- 信号相关信息
操作系统通过 PCB 管理进程,状态就是用来判断这个进程是否可以被调度器调度到 CPU 上运行。
二、Linux 内核的进程状态(内核源码定义)

内核源码中,state 是整数,不同数字代表不同状态。
1. R 运行状态(TASK_RUNNING)
包含两种场景: ① 进程正在 CPU 上执行; ② 进程已经准备就绪,放到运行队列里,等待 CPU 调度(就绪状态)。
✅ 关键点: Linux 内核把就绪态 + 运行态统一归类为 R 状态,不像课本分开。只要进程准备好了,随时可以上 CPU 执行,就是 R 状态。
查看进程状态命令:
ps aux
或者动态观察
top
2. S 睡眠状态(TASK_INTERRUPTIBLE)可中断睡眠
进程等待某个事件,主动放弃 CPU,进入睡眠。 可中断 :可以被信号唤醒。 场景举例:cin/cout等待用户输入、进程等待读磁盘数据,此时进程不占用 CPU,挂在等待队列。
通俗理解:进程在等资源,等待期间可以收到信号被唤醒。
3. D 深度睡眠(TASK_UNINTERRUPTIBLE)不可中断睡眠
不可中断睡眠,不能被信号唤醒 ! 这个状态非常关键,面试高频考点。 什么时候出现:进程正在和硬件交互(比如读写磁盘),此时不能被打断。 如果此时收到 kill 信号,杀不掉 D 状态进程。
为什么设计 D 状态?防止进程在硬件 IO 操作中途被打断,造成数据损坏。 现象:
kill -9也无法杀死 D 状态进程,只能等 IO 完成,或者重启服务器。
4. T 停止状态(TASK_STOPPED)
进程被暂停执行,收到继续信号后可以恢复运行。 不是进程自己主动休眠,是外部信号让它停下。 典型场景:gdb 调试打断点,程序停下来,此时进程状态 T。
相关信号:
- SIGSTOP:暂停进程
- SIGCONT:唤醒继续运行

5. Z 僵尸状态(TASK_ZOMBIE)【重中之重】
子进程已经执行完毕、退出了,但是父进程没有读取子进程的退出信息。 子进程 PCB 不会被操作系统释放,保留退出状态信息,等待父进程回收。此时子进程就是僵尸进程,状态标记 Z。
核心特点:
- 子进程代码、资源全部释放,只剩 PCB 残留;
- 占用少量内存资源;
- 如果父进程长期不回收,大量僵尸进程会占用 pid 号,造成 pid 资源泄露;
kill无法杀死僵尸进程,因为进程本身已经结束,只是 PCB 没回收。
来⼀个创建维持30秒的僵死进程例⼦:
如何回收僵尸进程:
- 父进程调用
wait()/waitpid(),等待并读取子进程退出码,操作系统释放子进程 PCB; - 父进程先退出,子进程变成孤儿进程,被 1 号进程 init 收养,init 会自动回收僵尸子进程。
6. X 死亡状态(TASK_DEAD)
进程即将被系统彻底释放,PCB 马上销毁,这个状态非常短暂,几乎很难在 ps 命令中观察到。
三、孤儿进程
父进程提前退出,子进程还在运行,这个子进程叫做孤儿进程。 Linux 机制:孤儿进程会被init进程(pid=1)收养,变成 init 的子进程。 好处:当孤儿进程退出,init 进程会自动调用 wait 回收它,不会变成僵尸进程。
孤儿进程无害,系统自动兜底回收;僵尸进程是资源泄露问题,需要程序员处理。
孤儿进程演示代码
cpp
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t id = fork();
if(id == 0)
{
//子进程
printf("子进程 pid:%d, 父进程pid:%d\n",getpid(),getppid());
sleep(5);
printf("子进程 pid:%d, 父进程pid:%d\n",getpid(),getppid());
}
else
{
//父进程,直接退出
sleep(1);
printf("父进程退出\n");
}
return 0;
}

运行现象:父进程先退出,5 秒后子进程打印 ppid 变成 1,被 init 收养。
四、僵尸进程演示代码
cpp
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t id = fork();
if(id == 0)
{
//子进程,执行完直接退出
printf("子进程执行完毕,准备退出\n");
sleep(2);
}
else
{
//父进程一直循环,不调用wait回收子进程
while(1)
{
printf("父进程正在运行,不回收子进程\n");
sleep(1);
}
}
return 0;
}

编译运行,新开终端执行ps aux | grep a.out,2 秒后子进程退出,状态变成 Z 僵尸。
五、进程状态查看实操命令
# 查看所有进程,观察STAT那一列就是进程状态
ps aux
# 持续动态刷新观察进程状态
top
STAT 列除了字母,还会附带附加标记:
s:这个进程是会话首进程+:前台进程组l:多线程进程

六、进程优先级
操作系统不能平等对待所有进程,优先级决定谁优先使用 CPU。
优先级 = 谁优先被 CPU 调度。
查看优先级
ps -al
字段解释:
- PRI:进程优先级,内核调度使用,值越小优先级越高
- NI:nice 值,用来修正 PRI。范围:-20 ~ 19
- nice 越小,PRI 越小,优先级越高;
- 默认 nice 值是 0。
修改 nice 值:
cpp
# 启动程序的时候指定nice
nice -n -5 ./test
# 修改已经运行进程的nice
renice -5 -p 进程pid
root 用户可以设置负数,普通用户只能调高 nice(降低优先级),不能调高优先级。
七、进程的其他基础概念


1. 进程的独立性
每个进程有独立 PCB、独立虚拟地址空间。一个进程崩溃,不会直接影响其他进程。fork 创建子进程,采用写时拷贝,保证父子进程数据独立。
2. 进程组 & 会话
- 进程组:多个关联进程放在同一个进程组,拥有同一个进程组 id。fork 出来的父子进程默认在同一个进程组。
- 会话:一个会话包含多个进程组,一个会话对应一个终端。登录终端就创建一个会话。 前台进程组:直接占用终端,可以输入输出;后台进程不占用终端。
&把程序放到后台运行:
cpp
./test &
八、面试高频问题
Q1:R 状态代表进程一定正在 CPU 上运行吗?
不是。R 包含两种:正在 CPU 运行,或者在运行队列就绪等待调度。
Q2:D 状态进程 kill -9 能否杀掉?
不能。D 是不可中断睡眠,无法被信号打断,只能等待 IO 结束或者重启机器。
Q3:僵尸进程和孤儿进程区别?
孤儿进程:父进程先退出,子进程被 1 号进程收养,无害 。 僵尸进程:子进程退出,父进程不回收子进程退出信息,PCB 残留,会造成资源泄漏。kill 无法清除僵尸进程。
Q4:如何处理僵尸进程?
方案 1:父进程使用 wait/waitpid 阻塞或者非阻塞等待回收子进程; 方案 2:父进程注册 SIGCHLD 信号,子进程退出会发送 SIGCHLD 信号,在信号处理函数内部回收子进程(工程最常用); 方案 3:杀死父进程,僵尸进程变成孤儿,由 init 回收。
Q5:nice 值的范围和作用?
nice 取值范围[-20,19],用于调整进程优先级。nice 越小,优先级越高。普通用户只能增大 nice,不能设置负数。
九、小结
进程状态保存在 PCB 结构体中,Linux 一共定义 R/S/D/T/Z/X 这几种核心状态。重点区分僵尸进程、孤儿进程。 僵尸进程是开发中需要重点规避的问题,本质是子进程退出后资源没有被父进程回收。 优先级、进程组、会话都是操作系统管理大量进程的辅助机制,理解这些,才能看懂进程调度行为。

