前文介绍的几个底层机制使得进程切换成为可能。

调度器 (scheduler) 所采用的高层策略则决定了 OS「选择哪个进程进行切换」。

调度指标

CPU 突发 (CPU burst): 进程占用 CPU 的时间 $T_{burst}$。

周转时间 (turnaround time),表征效率:$T_{turnaround}=T_{completion}-T_{arrival}$
响应时间 (response time),表征公平:$T_{response}=T_{firstrun}-T_{arrival}$
等待时间 (wait time):$T_{wait}=T_{turnaround}-T_{burst}$

FIFO

先进先出 (First-In-First-Out, FIFO) 策略。

车队效应 (convoy effects):短进程可能被 CPU 密集型 (CPU-bounded) 进程阻塞,增大平均等待时间。

SJF

短任务优先 (Shortest-Job-First, SJF) 策略。

若所有任务的到达时间相同,SJF 策略最优。

非抢占式 (non-preemtive):进程一旦开始运行就会一直占据 CPU 直到终止。导致车队效应。
长进程饥饿 (starvation)

STCF

最短完成时间优先 (Shortest Time-to-Completion First, STCF) 策略。

SJF 的抢占式版本。

新到达的进程触发调度器,比较所有可运行进程(包括当前进程和新进程)剩余的执行时间,并切换到其中最短的那个。

若所有任务没有 I/O,STCF 策略最优。

RR

轮转 (Round-Robin, RR) 策略。

就绪队列中的每个进程依次按固定时间片 (time quantum) 轮流运行。就绪队列是 FIFO 的。

  • 时间片一定是计时器中断周期的整数倍

交互式 (interactive) 进程希望尽量缩短响应时间,适用于 RR。

周转时间指标很差。

有 I/O 的任务

I/O 将任务的执行过程切分成多个 CPU burst。

当任务发起 I/O 时,它释放 CPU 并离开就绪队列;I/O 完成后,任务重新回到就绪队列,并准备继续执行下一个 CPU burst。

MLFQ

一个优秀的调度算法应该满足:

  • 最小化交互式任务的响应时间
  • 在没有关于任务的先验知识的情况下,最小化周转时间(学习算法?)

让我们见见 多级反馈队列 (Multilevel Feedback Queue, MLFQ) 策略。

MLFQ 维护多个优先级不同的就绪队列,其中优先级较高的队列时间片较小,较低的队列时间片较大。每个队列有一个时间额度 (time allotment)。

  • 若 $\text{Priority}(A) > \text{Priority}(B)$,运行 $A$。
  • 若 $\text{Priority}(A) = \text{Priority}(B)$,根据该队列的时间片大小使用轮转调度。
  • 新任务进入最高优先级队列。
  • 若一个任务用完了所在队列的时间额度,将其降低至下一个较低优先级队列。
  • 以 $S$ 为周期将所有任务提升 (boost) 至最高优先级队列。

公平份额调度

公平份额调度 (fair share scheduling) 是进程组 (process groups) 级别的调度策略。

  • 想要优先属于同一应用的多个进程?
  • 多用户环境,保证每个用户所创建进程享有公平的份额?

彩票调度 (lottery scheduling):恭喜这位中奖的进程!你可以来占用 CPU 了!
步长调度 (stride scheduling)

多处理器调度

单队列多核调度。

  • 并发问题
  • 处理器亲和性 (CPU affinity) 问题

多队列调度。

  • 每个队列有自己的队列,新任务根据某个启发 (heuristic) 被分配给某个队列
  • 队列间负载平衡:工作窃取 (work stealing)