进程的概念

程序是静态的,是存放在磁盘中的可执行文件,例如 .exe 文件或 ELF 文件。

进程是动态的,是程序的一次执行过程。同一个程序可以被多次运行,每次运行都对应一个独立进程。

900

同一个程序的多个进程可以拥有相同的程序段,但它们的 PCB、数据段、资源占用和执行位置不同。比如同时登录多个账号,本质上是同一程序对应多个进程。

引入进程实体后,可以更准确地定义进程:

Important

进程是进程实体的运行过程,是系统进行资源分配和调度的独立单位。

# 进程的组成

进程运行前,程序指令要装入主存,运行中产生的数据也要有存放位置。操作系统还要保存管理该进程所需的信息。

进程实体也称进程映像,由程序段、数据段、PCB 三部分组成。

900

组成 内容 使用者
程序段 程序指令 CPU 取指并执行
数据段 运行中产生和使用的数据 进程自身
PCB 进程标识、状态、资源、调度和运行现场信息 操作系统

程序段和数据段与进程自己的运行逻辑有关;PCB 与操作系统的管理逻辑有关。

PCB

PCB 是 Process Control Block,即进程控制块。操作系统需要管理进程,而管理所需的信息都保存在 PCB 中。

PCB 是进程存在的唯一标志。创建进程时,操作系统创建 PCB;进程结束时,操作系统回收 PCB。PCB 被回收后,该进程就不再存在。

PCB 信息 内容 用途
进程描述信息 PID、UID 等 区分不同进程和所属用户
进程控制和管理信息 当前状态、优先级、运行统计信息等 支持调度和状态管理
资源分配清单 内存、打开文件、I/O 设备等 记录进程占用的系统资源
处理机相关信息 PC、PSW、通用寄存器、栈指针等 保存和恢复运行现场
PCB 不是进程的全部

PCB 是操作系统管理进程的控制信息。进程真正要执行的指令在程序段中,运行中读写的数据在数据段、堆、栈等区域中。

# 进程的特征
特征 含义
动态性 进程有创建、运行、暂停、终止等生命周期,这是进程最基本的特征
并发性 多个进程可以在时间上交替推进,宏观上像是同时运行
独立性 进程是资源分配和调度的独立单位
异步性 各进程以不可预知的速度向前推进,执行结果可能受调度顺序影响

程序是静态文件,不具有这些运行时特征。进程之所以具有动态性,是因为它会在不同状态之间转换;进程之所以能并发和异步推进,是因为操作系统能保存现场、恢复现场,并把进程放入合适的调度队列。

进程的状态

进程状态描述进程当前处于生命周期的哪个阶段,以及是否具备运行条件。

状态 含义 PCB/队列视角
创建态 操作系统正在创建进程 创建 PCB,分配必要资源,初始化信息
就绪态 除 CPU 外,其他运行条件已经具备 PCB 在就绪队列中等待调度
运行态 进程正在 CPU 上执行 单 CPU 下同一时刻最多一个进程运行,多核下可以多个进程运行
阻塞态 进程正在等待资源或事件,暂时不能继续执行 PCB 在某个阻塞队列中等待事件发生
终止态 进程已经结束,操作系统正在清理 回收资源,最后撤销 PCB

就绪态、运行态、阻塞态是最常见的三个基本状态。就绪态和阻塞态都没有占用 CPU,但原因不同:就绪态只差 CPU;阻塞态即使获得 CPU 也无法继续执行。

900

状态转换 触发原因 操作系统动作
创建态 $\to$ 就绪态 创建工作完成 初始化 PCB,把进程放入就绪队列
就绪态 $\to$ 运行态 被调度程序选中 恢复运行现场,把 CPU 分给该进程
运行态 $\to$ 就绪态 时间片用完、被抢占、主动让出 CPU 保存运行现场,把 PCB 放回就绪队列
运行态 $\to$ 阻塞态 请求 I/O、等待资源、等待事件 保存运行现场,把 PCB 放入对应阻塞队列
阻塞态 $\to$ 就绪态 等待事件发生或资源可用 修改状态,把 PCB 移入就绪队列
运行态 $\to$ 终止态 正常退出、异常结束、被终止 进程下 CPU,回收资源,最后撤销 PCB
阻塞态不能直接转为运行态

阻塞进程等待的事件发生后,只是重新具备运行条件,应先转入就绪态。是否立即运行,由调度程序决定。

# 进程的组织

PCB 中通常有 state 字段表示当前状态。为了管理同一状态下的多个进程,操作系统还会把 PCB 组织起来。

900

常见组织方式有两种:

组织方式 做法 例子
链接方式 用指针把同类 PCB 连成队列 就绪队列、阻塞队列
索引方式 用索引表记录同类 PCB 的地址 就绪索引表、阻塞索引表

阻塞队列通常不止一个。等待打印机、等待磁盘 I/O、等待某个信号量的进程,可以放入不同阻塞队列。事件发生时,操作系统沿着对应队列找到需要唤醒的进程。

进程控制

进程控制是操作系统对进程生命周期和状态转换的管理,包括创建新进程、撤销已有进程、阻塞进程、唤醒进程和切换进程。

进程控制不是只改一个状态标签,而是要同时维护 PCB、队列和资源。

一次进程控制通常涉及三类操作:

  1. 更新 PCB 中的信息,例如修改 state
  2. 将 PCB 插入合适队列,或从原队列中移出。
  3. 分配或回收资源。

如果进程要离开 CPU,还要保存运行现场;如果进程要开始运行,还要恢复运行现场。

原语

进程控制通常由原语实现。原语是运行在内核态的一段特殊程序,执行时具有原子性,即执行过程不可被中断。

原语必须原子执行,是因为进程控制常常要同时修改多个内核数据结构。以唤醒进程为例,操作系统至少要做两件事:

  1. 把 PCB 中的 state 从阻塞态改为就绪态。
  2. 把 PCB 从阻塞队列移到就绪队列。

如果第一步完成后被中断,系统可能出现“PCB 的状态是就绪,但 PCB 仍在阻塞队列中”的不一致。

原语的原子性可以通过关中断和开中断实现。关中断和开中断是特权指令,只能在内核态执行。若普通用户程序可以随意关中断,系统可能无法响应时钟中断、I/O 中断和调度请求。

常见进程控制原语

原语 典型状态变化 主要工作
创建原语 无 $\to$ 创建态 $\to$ 就绪态 申请空白 PCB,分配资源,初始化 PCB,插入就绪队列
撤销原语 运行/就绪/阻塞 $\to$ 终止态 $\to$ 无 终止进程,回收资源,撤销 PCB
阻塞原语 运行态 $\to$ 阻塞态 保存现场,修改状态,插入对应阻塞队列,调度其他进程
唤醒原语 阻塞态 $\to$ 就绪态 根据事件找到阻塞进程,修改状态,移入就绪队列
切换原语 运行态 $\leftrightarrow$ 就绪态 保存当前进程现场,恢复新进程现场

阻塞原语和唤醒原语通常成对出现。因何事阻塞,就应由何事唤醒。等待磁盘 I/O 的进程,应在对应 I/O 完成后被唤醒;等待某个信号量的进程,应在该信号量可用后被唤醒。

上下文切换

上下文是进程继续执行所需的运行现场,典型内容包括 PC、PSW、通用寄存器、栈指针以及其他体系结构相关寄存器。

进程运行时,中间结果和下一条指令地址可能保存在 CPU 寄存器中。进程离开 CPU 前必须保存这些内容,否则下次无法从原位置继续执行。

一次上下文切换通常包括:

  1. 把当前运行进程的 CPU 现场保存到它的 PCB。
  2. 修改当前进程状态,把 PCB 放入合适队列。
  3. 从就绪队列中选择下一个进程。
  4. 从新进程 PCB 恢复 CPU 现场。
  5. 新进程从上次停下的位置继续执行。

上下文切换不是普通函数调用。它改变了 CPU 正在服务的进程,也改变了当前运行现场对应的地址空间、栈和寄存器集合。