这是“操作系统系列教程”的第七篇。上一篇我们讲了进程,知道了它是操作系统分配资源的基本单位。但操作系统到底是怎么“记住”一个进程的?它怎么知道有哪些进程、每个进程处于什么状态、该用哪些资源?答案就藏在一个关键的数据结构里——进程控制块(PCB)。

操作系统如何“记住”一个进程?

先来想一个问题:操作系统同时管理着几十上百个进程,它怎么知道每个进程的存在?

当你打开任务管理器,看到一长串进程列表,每个进程都有 PID、内存占用、CPU 占用、状态等信息。这些信息不是凭空产生的,而是操作系统在创建进程时,为每个进程建立了一份“档案”。这份档案,就是进程控制块(Process Control Block,PCB)。

没有 PCB,操作系统就无法感知进程的存在。进程一旦创建,PCB 也随之建立;进程一旦终止,PCB 也随之销毁。可以说,PCB 是进程存在的唯一标志。

这篇文章,我们就来把 PCB 这件事讲清楚。

说明:本文涉及数据结构、操作系统内部实现等知识。初学者如果遇到暂时看不懂的术语,可以先跳过细节,重点理解“PCB 是操作系统管理进程的唯一依据,记录了进程的所有信息”这一核心思想。

一、PCB 到底是什么?

1.1 从生活场景理解

我们可以用“学生档案”来类比 PCB。

学校场景操作系统
学生进程
学生档案PCB
档案中的姓名、学号、班级PID、进程状态、优先级
档案中的成绩单CPU 使用时间、内存占用
档案管理员操作系统内核

学校要管理学生,必须为每个学生建立档案。档案里记录了学生的所有信息,学校通过档案来了解学生、管理学生。同样,操作系统要管理进程,必须为每个进程建立 PCB,通过 PCB 来感知进程、调度进程、分配资源。

1.2 PCB 的定义

给出一个正式的定义:

进程控制块(PCB)是操作系统为了管理进程而创建的一个数据结构,它记录了进程的所有信息,是进程存在的唯一标志。

这个定义里有三个关键点:

  1. 数据结构:PCB 本质上是一个结构体,包含多个字段;
  2. 记录所有信息:进程的标识、状态、资源、优先级等都在 PCB 中;
  3. 唯一标志:操作系统通过 PCB 来感知进程的存在,没有 PCB 就没有进程。

1.3 PCB 在系统中的位置

硬件

内核

进程

记录进程信息

记录进程信息

记录进程信息

记录进程信息

调度

分配

管理

代码段

数据段

堆

栈

PCB
进程控制块

CPU

内存

磁盘

图 1:PCB 在系统中的位置。 PCB 是内核中的数据结构,记录了进程的所有信息,是操作系统管理进程的唯一依据。

从图 1 可以看出,PCB 并不在进程的用户空间里,而是位于内核空间。进程本身可能只能访问自己的代码、数据、堆、栈,但 PCB 由内核维护,进程无法直接修改。

二、为什么需要 PCB?

2.1 没有 PCB 会怎样?

假设操作系统没有 PCB,会发生什么?

  • 操作系统不知道有哪些进程存在;
  • 不知道每个进程处于什么状态;
  • 不知道每个进程占用了哪些资源;
  • 不知道下一个该调度哪个进程;
  • 进程切换时,不知道保存和恢复什么信息。

没有 PCB,操作系统就像没有档案的学校,完全无法管理学生。进程将变成一团乱麻,系统无法正常运转。

2.2 PCB 的核心作用

PCB 的作用可以归纳为四个方面:

作用说明
标识进程通过 PID 唯一标识每个进程
记录状态记录进程当前处于就绪、运行还是阻塞
保存上下文进程切换时保存和恢复 CPU 寄存器、程序计数器等
管理资源记录进程占用的内存、打开的文件、使用的设备等

在这里插入图片描述

图 2:PCB 的四大核心作用。 标识、记录、保存、管理。

三、PCB 包含哪些信息?

PCB 中到底存了哪些东西?不同操作系统的实现略有差异,但核心信息大致相同。我们可以把它分为以下几类。

3.1 进程标识信息

字段说明
进程 ID(PID)唯一标识一个进程
父进程 ID(PPID)创建该进程的父进程 ID
用户 ID(UID)启动该进程的用户
组 ID(GID)用户所属的组

3.2 进程状态信息

字段说明
进程状态新建、就绪、运行、阻塞、终止
优先级调度优先级
时间片剩余可执行时间
等待事件阻塞时等待的事件类型

3.3 CPU 上下文信息

字段说明
程序计数器(PC)下一条要执行的指令地址
通用寄存器保存进程执行时的寄存器值
栈指针(SP)指向当前栈顶
程序状态字(PSW)标志位、特权级等

3.4 内存管理信息

字段说明
页表基址指向该进程的页表
内存限制代码段、数据段、堆、栈的边界
内存占用已分配的内存大小

3.5 文件与设备信息

字段说明
打开文件列表该进程打开的所有文件
文件描述符表文件描述符到文件对象的映射
设备列表该进程占用的设备

3.6 统计与调度信息

字段说明
CPU 使用时间进程累计占用的 CPU 时间
启动时间进程创建的时间
子进程列表该进程创建的子进程
信号处理信号处理函数的地址

PCB

进程标识

进程状态

CPU 上下文

内存管理

文件与设备

统计与调度

PID · PPID · UID

状态 · 优先级 · 时间片

PC · 寄存器 · 栈指针

页表 · 内存边界

打开文件 · 设备

CPU时间 · 启动时间

图 3:PCB 的主要内容。 六大类信息,覆盖进程管理的方方面面。

四、PCB 的组织方式

系统中同时存在很多进程,也就有很多 PCB。操作系统如何组织这些 PCB,才能高效地查找、插入、删除?

常见的组织方式有三种:链表、索引表、队列。

4.1 链表方式

把所有 PCB 用链表串起来,操作系统通过遍历链表来查找进程。

在这里插入图片描述

图 4:PCB 链表组织方式。 通过指针把 PCB 串联起来。

优点:实现简单,插入删除方便。
缺点:查找效率低,需要遍历。

4.2 索引表方式

操作系统维护一张索引表,表中每一项指向一个 PCB。通过 PID 可以直接定位到 PCB。

在这里插入图片描述

图 5:PCB 索引表组织方式。 通过 PID 直接定位 PCB,查找效率高。

优点:查找效率高,O(1) 时间复杂度。
缺点:需要额外的索引表空间。

4.3 队列方式

按照进程状态,把 PCB 放入不同的队列:就绪队列、阻塞队列、运行队列等。

在这里插入图片描述

图 6:PCB 队列组织方式。 按状态分队列,调度器直接从对应队列中选取进程。

优点:调度方便,直接操作对应队列。
缺点:状态转换时需要移动 PCB。

在实际操作系统中,这三种方式通常会结合使用。例如,Linux 使用链表和红黑树来组织 PCB,同时维护多个队列来支持调度。

五、Linux 中的 PCB:task_struct

在 Linux 中,PCB 对应的数据结构是 task_struct。它是一个非常庞大的结构体,定义在 include/linux/sched.h 中。

5.1 task_struct 的主要字段

字段说明
pid进程 ID
state进程状态
prio调度优先级
mm内存管理信息
files打开文件信息
threadCPU 上下文
parent父进程指针
children子进程链表

5.2 task_struct 的规模

task_struct 的大小在不同内核版本中有所不同,通常在几 KB 到十几 KB 之间。它包含了进程的所有信息,是内核中最重要的数据结构之一。

你可以用下面的命令查看 Linux 内核中 task_struct 的定义:

grep -n "struct task_struct" /usr/src/linux-headers-$(uname -r)/include/linux/sched.h

5.3 进程与 PCB 的对应关系

在 Linux 中,每个进程有且只有一个 task_struct。内核通过 task_struct 来管理进程的一切。

在这里插入图片描述

图 7:Linux 中进程与 task_struct 的对应关系。 每个进程对应一个 task_struct。

六、PCB 与进程状态转换

进程状态的变化,本质上就是 PCB 中状态字段的变化。当进程从就绪变为运行,PCB 中的状态字段从“就绪”改为“运行”;当进程从运行变为阻塞,状态字段从“运行”改为“阻塞”。

在这里插入图片描述

图 8:进程状态转换与 PCB。 状态变化时,PCB 中的状态字段和所在队列都会更新。

从图 8 可以看出,PCB 不仅记录了进程状态,还通过队列组织方式,帮助操作系统快速找到对应状态的进程。

七、PCB 的创建与销毁

7.1 PCB 的创建

当创建一个新进程时,操作系统会:

  1. 分配一个空闲的 PCB;
  2. 填写 PCB 中的各个字段;
  3. 把 PCB 插入就绪队列;
  4. 分配 PID;
  5. 分配内存等资源。

在这里插入图片描述

图 9:PCB 的创建过程。 从分配 PCB 到插入就绪队列。

7.2 PCB 的销毁

当进程终止时,操作系统会:

  1. 回收进程占用的内存、文件等资源;
  2. 把 PCB 从队列中移除;
  3. 释放 PCB;
  4. 通知父进程。

如果父进程没有及时回收,PCB 会保留,形成僵尸进程。僵尸进程占用的主要就是 PCB 资源。

八、常见误区澄清

误区真相
“PCB 是进程的一部分”PCB 位于内核空间,由内核维护,不属于进程的用户空间
“没有 PCB 进程也能运行”PCB 是进程存在的唯一标志,没有 PCB 就没有进程
“PCB 只记录 PID”PCB 记录了进程的所有信息,包括状态、上下文、资源等
“PCB 越大越好”PCB 过大会浪费内存,需要在信息完整和空间效率之间平衡
“进程终止后 PCB 立即消失”如果父进程未回收,PCB 会保留,形成僵尸进程
“所有操作系统的 PCB 都一样”Linux 用 task_struct,Windows 用 EPROCESS,结构不同
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐