2.2 进程管理
操作系统进程管理核心知识点整理
一、进程的组成
进程实体由三部分组成:
- PCB(Process Control Block):操作系统感知进程存在的唯一标识,记录了进程的标识信息、处理机状态、调度信息、控制信息(如资源清单、记账信息等)。
- 程序段:描述进程要完成的功能,即"做什么"。
- 数据段:程序执行时所需的工作数据。
三者关系可概括为:PCB 是进程存在的标志,程序段定义了行为,数据段承载了状态。
二、进程状态模型
进程状态采用五态模型(在三态模型基础上扩展新建态和终止态):
┌─────────────────────────────────────┐
│ │
▼ │
┌──────────┐ 时间片到/ ┌──────────┐ │
新建 ──→ │ 就绪 │ ◄──被抢占──── │ 运行 │──┘
(New) │ (Ready) │ ────────────► │(Running) │
└──────────┘ 高优先级到来 └──────────┘
▲ │
│ │ 请求资源/等待事件
│ ▼
│ ┌──────────┐
│ │ 阻塞 │
│ │(Blocked) │
│ └──────────┘
│ │
│ 资源到位/事件发生│
└──────────────────┘
│
▼
┌──────────┐
│ 终止 │
│(Terminated)│
└──────────┘
各状态说明:
| 状态 | 含义 |
|---|---|
| 新建(New) | 进程刚被创建,尚未被提交到就绪队列,系统正在为其分配资源 |
| 就绪(Ready) | 已具备运行条件,等待 CPU 分配 |
| 运行(Running) | 正在 CPU 上执行 |
| 阻塞(Blocked) | 因等待某事件(如 I/O 完成、资源可用)而暂停执行 |
| 终止(Terminated) | 执行结束,等待操作系统回收资源、进行善后处理 |
关键转换路径:
- 就绪 → 运行:被调度程序选中,获得 CPU
- 运行 → 就绪:时间片用完,或被更高优先级进程抢占
- 运行 → 阻塞:主动请求资源或等待事件(如 I/O)
- 阻塞 → 就绪:等待的事件已发生,资源已到位
- 运行 → 终止:进程执行完毕
三、前趋图
前趋图(Precedence Graph)是一个有向无环图(DAG),用来表示任务间的并行关系和先后顺序关系。节点表示任务,有向边表示任务间的执行先后约束。
┌───┐
│ A │──┐
└───┘ │
│
┌───┐ │ ┌───┐ ┌───┐
│ B │──┼──►│ D │──────►│ E │
└───┘ │ └───┘ └───┘
│
┌───┐ │
│ C │──┘
└───┘
从图中可以读出以下信息:
- A、B、C 可以并行执行:三者之间没有有向边连接,不存在先后约束。
- A、B、C 必须全部完成后才能执行 D:A→D、B→D、C→D 三条有向边构成了汇聚关系。
- D 完成后才能执行 E:D→E 表示严格的先后依赖。
前趋图的核心价值在于:可视化地表达任务间的并行性与串行性约束,是分析进程调度、同步机制的重要工具。
四、进程资源图
进程资源图用来表示进程和资源之间的分配和请求关系。图中资源节点在上方,进程节点在下方,请求边由进程指向资源,分配边由资源指向进程。
┌──────────┐ ┌──────────┐
│ │ │ │
│ R1 │ │ R2 │
│ ○ ○ │ │ ○ ○ ○ │
│ │ │ │
└──┬────┬──┘ └──┬───┬──┘
│ │ │ │
分配 │ │ 分配 分配 │ │ 请求
│ │ │ │
▼ ▼ ▼ │
┌──┐ ┌──┐ ┌──┐ │
│P1│ │P3│ │P2│ │
└┬─┘ └┬─┘ └┬─┘ │
│ │ │ │
│ │ │ │
请求 ──────┘ └──── 请求 ────┘ │
│
└──────── 请求 ───────────┘
图例说明:
| 符号 | 含义 |
|---|---|
| R1(2个○) | 资源R1共有2个实例 |
| R2(3个○) | 资源R2共有3个实例 |
| R1 → P1, P3 | R1的2个实例分别分配给了P1和P3 |
| R2 → P2 | R2的1个实例分配给了P2(还剩2个空闲) |
| P1 → R2 | P1正在请求R2 |
| P2 → R1 | P2正在请求R1 |
| P3 → R2 | P3正在请求R2 |
阻塞节点与非阻塞节点的判定:
- P1(非阻塞):P1请求R2,R2共3个实例,已分配1个给P2,还剩2个空闲,可以满足P1的请求。
- P2(阻塞):P2请求R1,R1共2个实例,已全部分配给P1和P3,无空闲实例,P2的请求无法满足,被阻塞。
- P3(非阻塞):P3请求R2,R2还剩2个空闲实例,可以满足P3的请求。
死锁判定: 当进程资源图中所有进程都是阻塞节点,且存在环路时,系统陷入死锁状态。本例中P1和P3均为非阻塞节点,因此系统未发生死锁。
进程资源图的化简方法(正确性判定):
- 统计系统中各资源的剩余空闲实例数。
- 找到一个非阻塞进程(其请求可被满足),将其所有边去除(变为孤立点)。
- 回收该进程占有的所有资源,增加系统空闲资源数。
- 重复步骤 2-3,直到所有进程都变成孤立点(系统安全),或剩余进程全部阻塞且无法化简(系统不安全/死锁)。
本例化简过程:
- 初始状态:R1空闲0个,R2空闲2个。
- P1是非阻塞节点(R2有空闲),化简P1:去除P1的所有边,回收P1占有的R1 → R1空闲变为1个。
- P2变为非阻塞节点(R1有1个空闲),化简P2:去除P2的所有边,回收P2占有的R2 → R2空闲变为3个。
- P3是非阻塞节点(R2有空闲),化简P3:去除P3的所有边,回收P3占有的R1 → R1空闲变为2个。
- 所有进程均被化简为孤立点 → 系统安全,未发生死锁。
五、互斥与同步
互斥和同步并非反义词,两者是并发控制的两种不同协调方式,不是对立面。
互斥(Mutual Exclusion): 多个进程对共享资源的排他性访问,同一时刻只允许一个进程使用临界资源,需要通过加锁/解锁来实现。
同步(Synchronization): 多个进程之间存在执行次序上的依赖关系,需要通过协调机制保证它们按照约定的顺序执行。例如:进程 A 生产数据,进程 B 消费数据,B 必须等 A 完成生产后才能消费——这就是同步。
互斥与同步的核心区别:
| 维度 | 互斥 | 同步 |
|---|---|---|
| 解决的问题 | 谁能访问共享资源(排他性) | 进程间的执行顺序(先后依赖) |
| 制约类型 | 间接制约(因竞争资源) | 直接制约(因协作任务) |
| 典型场景 | 多个进程争用打印机 | 生产者先生产,消费者后消费 |
| 本质 | 控制"能不能访问" | 控制"什么时候执行" |
互斥可以看作同步的一种特殊情况——它本质上也是对访问顺序的协调(强制串行化),但同步的外延远大于互斥。
六、信号量机制
6.1 基本概念
- 临界资源(Critical Resource):一次仅允许一个进程使用的共享资源,如打印机、共享变量等。
- 临界区(Critical Section):每个进程中访问临界资源的那段代码。
- 信号量(Semaphore):由 Dijkstra 提出的整型计数器,配合 P/V 两个原子操作实现进程同步与互斥。
6.2 两类信号量
| 信号量类型 | 初值 | 用途 |
|---|---|---|
| 互斥信号量 | 1 | 保护临界区,确保同一时刻仅一个进程进入 |
| 同步信号量 | 0 或资源可用数量(视场景而定) | 协调进程间执行顺序或控制资源配额 |
互斥信号量初值为 1 的原因:
- 初值为 1 表示"资源可用,允许一个进程进入"。
- 第一个进程执行 P 操作后,信号量变为 0,表示"资源已被占用"。
- 后续进程再执行 P 操作,信号量变为 -1,进程被阻塞等待。
同步信号量的初值需根据具体场景确定:
- 用于前驱关系同步时,初值通常为 0(等待事件尚未发生)。
- 用于资源计数时,初值为可用资源的数量(如缓冲区大小)。
6.3 P/V 操作原理
P 操作是主动的带有判断性质的 -1,V 操作是被动地因为某些操作产生的 +1。
P(S) 操作(申请资源):
S = S - 1
if S < 0:
将当前进程阻塞,插入 S 的等待队列
else:
进程继续执行
V(S) 操作(释放资源):
S = S + 1
if S <= 0:
从 S 的等待队列中唤醒一个进程
else:
进程继续执行
生产者-消费者问题中的 PV 操作示例:
信号量定义:
S0 (mutex) = 1 -- 互斥信号量,保护仓库的互斥访问
S1 (empty) = N -- 同步信号量,表示仓库空闲位数(N为仓库容量)
S2 (full) = 0 -- 同步信号量,表示仓库中已有的商品数
生产者进程:
P(S0) -- 申请仓库的互斥使用权
P(S1) -- 判断仓库是否有空位(S1>0则有空位)
将商品放入仓库
V(S2) -- 商品数+1(通知消费者有商品可取)
V(S0) -- 释放仓库互斥使用权
消费者进程:
P(S0) -- 申请仓库的互斥使用权
P(S2) -- 判断仓库是否有商品(S2>0则有商品)
从仓库取出商品
V(S1) -- 空位数+1(通知生产者有空位可放)
V(S0) -- 释放仓库互斥使用权
注意: 上述示例中 P 操作的顺序(先互斥后同步)在某些情况下可能导致死锁。实际工程中应遵循"先同步后互斥"的原则,即先执行 P(S1)/P(S2),再执行 P(S0),以避免死锁。
七、进程调度方式与调度算法
7.1 调度方式
分为可剥夺(抢占式)和不可剥夺(非抢占式)两种:
- 可剥夺(Preemptive):当更高优先级进程到来时,系统强行收回当前进程的 CPU,分配给高优先级进程。
- 不可剥夺(Non-preemptive):即使有更高优先级进程到来,也必须等待当前进程主动释放 CPU(如运行完毕或主动阻塞)。
7.2 三级调度
| 调度级别 | 别名 | 功能 | 频率 |
|---|---|---|---|
| 高级调度 | 长调度、作业调度、接纳调度 | 决定后备队列中哪个作业调入内存成为就绪进程 | 最低 |
| 中级调度 | 中程调度、对换调度 | 决定交换区中哪个进程调入内存参与 CPU 竞争 | 中等 |
| 低级调度 | 短程调度、进程调度 | 决定内存中哪个就绪进程获得 CPU | 最高、最频繁 |
低级调度是操作系统中最活跃、最重要的调度程序,对系统性能影响最大。
7.3 调度算法
| 算法 | 核心思想 | 适用场景 | 优缺点 |
|---|---|---|---|
| FCFS | 先来先服务 | 宏观调度/批处理 | 简单公平,但有"护航效应"(短作业被长作业阻塞) |
| 时间片轮转(RR) | 每个进程分配固定时间片,轮流执行 | 分时系统/微观调度 | 公平、响应快;时间片太小则切换开销大,太大则退化为 FCFS |
| 优先级调度 | 优先级高的进程优先获得 CPU | 实时系统 | 可区分任务重要性;但低优先级进程可能"饥饿" |
| 多级反馈队列 | 多个优先级队列 + 不同时间片 + 动态降级 | 通用操作系统 | 兼顾短作业快速完成和长作业逐步获得更长 CPU 时间 |
多级反馈队列的工作流程:
- 设置多个就绪队列 Q1、Q2、...、Qn,优先级依次递减。
- 每个队列分配不同的时间片长度(Q1 最短,Qn 最长)。
- 新进程进入 Q1 末尾,按 FCFS 排队执行。
- 若在 Q1 的时间片内未完成,则降级到 Q2 末尾。
- 以此类推,逐层降级。
这种设计使得短作业能在高层快速完成,长作业在低层获得较长的连续执行时间,是一种兼顾响应时间和吞吐量的优秀调度策略。
八、死锁问题
8.1 死锁定义
当一个进程在等待永远不可能发生的事件时,就会产生死锁。若系统中有多个进程处于死锁状态,就会造成系统死锁。
8.2 死锁产生的四个必要条件
| 条件 | 标准名称 | 含义 |
|---|---|---|
| 1 | 互斥条件 | 资源一次只能被一个进程使用 |
| 2 | 请求与保持条件 | 进程已持有至少一个资源,又请求新资源,且不释放已占资源 |
| 3 | 不可剥夺条件 | 资源一旦分配,不能被强制收回 |
| 4 | 循环等待条件 | 存在进程-资源的环形等待链(P1 等 P2 的资源,P2 等 P3 的,...,Pn 等 P1 的) |
四个条件必须同时满足才会产生死锁,只要破坏其中任意一个即可避免死锁。
8.3 死锁处理策略
死锁处理策略
├── 死锁预防:破坏四个必要条件之一,确保死锁永远不会发生(保守策略)
├── 死锁避免:运行时动态判断,确保系统始终处于安全状态(银行家算法)
├── 死锁检测:允许死锁发生,但定期检测并发现死锁
└── 死锁解除:检测到死锁后采取措施解除(剥夺资源、撤销进程等)
银行家算法的核心思想: 在每次资源分配前,先模拟分配后的系统状态,判断是否存在一个"安全序列"——即是否存在一种进程执行顺序,使得每个进程都能获得所需资源并顺利完成。若存在安全序列,则分配;否则拒绝。相当于借贷时提前考虑对方还得起才借钱。
8.4 死锁资源计算
系统内有 n 个进程,每个进程都需要 R 个同类资源:
- 发生死锁的最大资源数:n × (R - 1)
- 不发生死锁的最小资源数:n × (R - 1) + 1
推导过程:
- 最坏情况:每个进程都获得了 R-1 个资源,但都在等待最后一个资源,此时所有进程都被阻塞,形成死锁。此时已分配资源总数 = n×(R-1)。
- 避免死锁:只需再多 1 个资源,即 n×(R-1)+1,就能保证至少有一个进程获得全部 R 个资源并完成执行,释放其占有的资源,从而打破死锁。
九、线程
传统进程具有两个基本属性:可拥有资源的独立单位、可独立调度和分配的基本单位。
引入线程的原因:进程在创建、撤销和切换中,系统必须为之付出较大的时空开销,故在系统中设置的进程数目不宜过多,进程切换的频率不宜太高,这就限制了并发程度的提高。引入线程后,将传统进程的两个基本属性分开:
- 线程作为调度和分配的基本单位
- 进程作为独立分配资源的单位
用户可以通过创建线程来完成任务,以减少程序并发执行时付出的时空开销。
线程的核心特征:
| 特征 | 说明 |
|---|---|
| 不拥有资源 | 线程基本上不拥有系统资源,只持有运行必需的少量资源(程序计数器、寄存器组、栈) |
| 共享进程资源 | 同一进程内的线程共享该进程的代码段、数据段、打开的文件、信号量等 |
| 独立调度 | 线程是 CPU 调度和分派的基本单位 |
| 独有资源 | 线程栈指针、线程局部存储(TLS)、线程 ID 等标识数据不共享 |
进程与线程的对比:
| 维度 | 进程 | 线程 |
|---|---|---|
| 资源拥有 | 拥有独立的地址空间和资源 | 共享所属进程的资源 |
| 调度单位 | 传统 OS 中是调度单位 | 引入线程后成为调度单位 |
| 切换开销 | 大(需切换地址空间) | 小(仅保存/恢复寄存器和栈指针) |
| 通信方式 | 需 IPC 机制(管道、共享内存等) | 直接读写共享内存(需同步机制) |
| 隔离性 | 高(一个崩溃不影响其他) | 低(一个崩溃可能导致整个进程终止) |

浙公网安备 33010602011771号