Skip to content

CPU 调度

概念

CPU 调度是操作系统内核的核心功能之一:当多个进程(或线程)同时处于就绪状态时,调度器决定下一个获得 CPU 时间片的是谁

调度器分为两层:

  • 长期调度器(作业调度器):控制多少进程进入内存,影响系统并发度。
  • 短期调度器(CPU 调度器):从就绪队列中选出下一个要运行的进程,频率极高(毫秒级)。

调度时机:进程从运行态切换到等待态、就绪态,或进程终止时,调度器介入。

核心原理

1. 调度基本概念

抢占式 vs 非抢占式

类型描述代表算法
非抢占式进程一旦获得 CPU,只有主动放弃(等待 I/O 或退出)才会让出FCFS、非抢占 SJF
抢占式调度器可在任意时刻强制剥夺当前进程的 CPURR、SRTF、优先级抢占

抢占式调度响应性更好,适合交互式和实时系统;但引入了上下文切换开销竞态条件

CPU 密集型 vs I/O 密集型

  • CPU 密集型:大部分时间在做计算,I/O 少(如视频编码、矩阵运算)。
  • I/O 密集型:频繁发起 I/O 请求,大部分时间在等待(如 Web 服务器、数据库查询)。

好的调度策略会优先调度 I/O 密集型进程,让其尽快发起 I/O,同时让 CPU 密集型进程在后台占满 CPU。

调度指标

指标含义
周转时间(Turnaround Time)进程从提交到完成的总时间
等待时间(Waiting Time)进程在就绪队列中等待的累计时间
响应时间(Response Time)提交请求到首次得到响应的时间
吞吐量(Throughput)单位时间内完成的进程数
CPU 利用率(CPU Utilization)CPU 处于忙碌状态的时间比例

不同场景的优化目标不同:批处理系统追求吞吐量和周转时间;交互式系统追求响应时间;实时系统追求截止期满足率。


2. 经典调度算法

FCFS(先来先服务,First-Come First-Served)

按到达顺序排队,非抢占式。

示例:进程 P1(运行 24ms)、P2(3ms)、P3(3ms)按顺序到达。

进程到达时间运行时间完成时间周转时间等待时间
P102424240
P203272724
P303303027

平均等待时间 = (0 + 24 + 27) / 3 = 17ms

护航效应(Convoy Effect):一个长进程阻塞后面所有短进程,导致整体性能下降。


SJF / SRTF(最短作业优先 / 最短剩余时间优先)

  • SJF:非抢占,选择预计运行时间最短的进程。
  • SRTF:抢占式版本,若新到进程的剩余时间更短,立即抢占当前进程。

理论上 SJF 给出最优平均等待时间,但实际问题在于:

  • 无法准确预知运行时间(通常用历史均值指数平均估算)。
  • 饥饿(Starvation):长进程可能永远得不到 CPU,因为不断有短进程插入。

RR(时间片轮转,Round Robin)

每个进程分配固定时间片(quantum),时间片用完后强制切换到下一个就绪进程,循环执行。

时间片大小的权衡

时间片过小时间片过大
响应时间好上下文切换开销小
上下文切换频繁,CPU 利用率下降退化为 FCFS,响应时间差

经验值:时间片通常设为 10~100ms,上下文切换时间约 0.1ms,开销占比控制在 1% 以内。


优先级调度

每个进程附带优先级,调度器始终选择优先级最高的进程(可抢占或非抢占)。

问题:优先级反转(Priority Inversion)

高优先级进程 H 等待低优先级进程 L 持有的锁,而中优先级进程 M 抢占了 L,导致 H 间接被 M 阻塞。

解决方案:

  • 优先级继承协议(Priority Inheritance Protocol, PIP):L 持有锁期间临时继承 H 的优先级,阻止 M 插队。
  • 优先级天花板协议(Priority Ceiling Protocol):锁的优先级上限等于所有可能持有该锁的进程中最高优先级,获取锁时直接提升至该上限。
  • 老化(Aging):随时间推移逐渐提升低优先级进程的优先级,防止饥饿。

MLFQ(多级反馈队列,Multi-Level Feedback Queue)

综合了 RR 与优先级调度,是现代通用操作系统调度的基础思想。

规则

  1. 多条队列,优先级从高到低,高优先级队列时间片短。
  2. 新进程进入最高优先级队列。
  3. 若一个进程用完时间片仍未完成,降级到下一优先级队列。
  4. 若一个进程在时间片内主动放弃 CPU(等待 I/O),保持当前优先级。
  5. 定期将所有进程提升到最高优先级(防止饥饿)。

效果:短进程(I/O 密集型)始终在高优先级队列获得快速响应;长进程(CPU 密集型)自然沉降到低优先级队列。无需提前知道运行时间,自适应性强。


调度算法对比表

算法抢占性优点缺点适用场景
FCFS非抢占实现简单,公平护航效应,平均等待时间长批处理系统
SJF非抢占最优平均等待时间需预知运行时间,长进程饥饿批处理系统
SRTF抢占最优平均等待时间切换开销大,饥饿理论最优基准
RR抢占响应时间均匀,无饥饿时间片设置敏感,上下文切换多交互式系统
优先级两者皆可支持差异化服务优先级反转,低优先级饥饿实时 / 嵌入式
MLFQ抢占自适应,兼顾吞吐与响应实现复杂,参数调优难通用操作系统

3. Linux CFS(完全公平调度器)

Linux 内核(2.6.23+)的默认调度器,用于普通(SCHED_NORMAL/SCHED_BATCH)进程。

核心思想:不分配固定时间片,而是让每个进程获得等比例的 CPU 时间——即"完全公平"。

vruntime(虚拟运行时间)

每个进程维护一个 vruntime 值,表示该进程已经消耗的"加权虚拟时间":

  • :实际运行时间。
  • weight:由 nice 值映射而来,nice 值越低(优先级越高),weight 越大,vruntime 增长越慢,因而获得更多 CPU 时间。

红黑树(Red-Black Tree)组织就绪队列

CFS 用红黑树按 vruntime 排序所有可运行进程,最左节点就是 vruntime 最小的进程,即下一个应该运行的进程。选择复杂度为 ,插入/删除同为

nice 值与权重映射

nice 值范围 -20(最高优先级)到 +19(最低优先级)。内核维护一张预计算的 prio_to_weight 表,相邻 nice 值之间权重比约为 1.25,使得 nice 值差 1 对应约 10% 的 CPU 时间差异。

为什么叫"完全公平"?

理想情况下,n 个权重相同的进程各获得 的 CPU 时间。CFS 通过不断调度 vruntime 最小的进程,使所有进程的 vruntime 趋于相等,在宏观上实现了按权重比例的公平分配。


4. 实时调度

硬实时 vs 软实时

类型描述示例
硬实时必须在截止期内完成,错过即系统失效汽车 ABS、飞控系统
软实时尽量在截止期内完成,偶尔错过可接受视频播放、音频流

Linux 实时调度策略

Linux 提供两种实时调度策略,优先级高于 CFS:

  • SCHED_FIFO:实时 FCFS,无时间片。进程一旦运行,除非主动放弃或被更高优先级进程抢占,否则一直运行。
  • SCHED_RR:实时 RR,有时间片。时间片用完后,同优先级的实时进程间轮转。

实时优先级范围为 1~99(数字越大优先级越高),均高于所有普通进程(优先级为 0)。

优先级反转与优先级继承协议

Linux POSIX 互斥锁支持 PTHREAD_PRIO_INHERIT 属性,启用后实现优先级继承:当高优先级线程等待锁时,持锁的低优先级线程临时提升至高优先级,确保其尽快释放锁,避免中间优先级线程横插。

面试常问 & 怎么答

Q1:常见的 CPU 调度算法有哪些?各有什么优缺点?

先列举算法名称,再抓核心特点:FCFS 简单但有护航效应;SJF 理论最优但无法预知运行时间且有饥饿;RR 响应均匀但时间片选择敏感;优先级调度灵活但有优先级反转风险;MLFQ 综合最优,现代 OS 的基础。面试时重点展开 MLFQ 的设计思路(多队列 + 反馈降级 + 定期提升)和 RR 的时间片权衡,体现系统性思维。

Q2:Linux 用的是什么调度算法?CFS 是怎么工作的?

回答分三层:① 背景——Linux 2.6.23 引入 CFS 替代旧的 O(1) 调度器;② 核心机制——vruntime 记录加权虚拟时间,红黑树排序就绪队列,始终调度 vruntime 最小的进程;③ 公平性——nice 值通过 prio_to_weight 表映射权重,权重影响 vruntime 增长速率,从而按比例分配 CPU。能画出红黑树示意图或写出 vruntime 公式会加分。

Q3:什么是优先级反转?怎么解决?

先描述场景:高优先级进程 H 因等待低优先级进程 L 持有的共享资源而阻塞,中优先级进程 M 抢占 L,导致 H 间接等待 M——这就是优先级反转。然后给出解决方案:优先级继承协议(L 临时继承 H 的优先级)和优先级天花板协议(获锁时提升至预设上限)。可以提 Mars Pathfinder 真实案例(1997 年 NASA 火星探路者遭遇优先级反转导致系统重启),展示工程经验。

看到什么就先想到这类

关键词 / 场景联想到
进程等待时间长、短进程被阻塞FCFS 护航效应
调度算法理论最优SJF/SRTF,但注意饥饿
交互式系统、响应时间均匀RR 时间片轮转
高优先级进程莫名阻塞优先级反转,考虑优先级继承
Linux 普通进程调度CFS + vruntime + 红黑树
Linux 实时进程SCHED_FIFO / SCHED_RR,优先级 1~99
系统需要同时兼顾响应和吞吐MLFQ 多级反馈队列
nice 值 / 进程优先级调整CFS 权重映射,影响 vruntime 增长速率