进程调度
多个进程同时处于就绪状态时,CPU只能先选一个执行。选择哪一个、让它运行多久,由操作系统的CPU调度决定。进程的状态与PCB见 进程;下面只讨论就绪进程之间怎样分配CPU。调度策略直接影响平均等待时间、响应速度和进程之间的公平性:进程集合相同,换一种执行顺序就可能让短进程多等很久,也可能让交互式操作变得迟钝。本页说明调度器在哪些队列之间做选择、四种常见调度算法各自怎样工作,以及用哪些指标比较它们的代价。
定义
操作系统的调度器决定哪个就绪进程获得CPU,以及获得多久。按能否打断正在运行的进程,调度分为两类:
- 非抢占式调度:进程一旦获得CPU,就一直运行到结束或主动进入阻塞,中途不会被换下。
- 抢占式调度:进程可以在运行途中被打断,例如时间片用完,或有更紧迫的进程变为就绪;被打断的进程回到就绪队列等待下一次调度。
一次调度决策通常出现在四种时机:进程从运行转为阻塞、时间片用完或进程被抢占、阻塞的进程转为就绪、进程终止。是否在这些时机立刻切换进程,取决于系统采用抢占式还是非抢占式调度。
调度队列
操作系统用不同的队列组织处于不同阶段的进程。
| 队列 | 存放的进程 | 说明 |
|---|---|---|
| 作业队列 | 系统中的所有进程 | 包括尚未装入内存的进程 |
| 就绪队列 | 已装入内存、准备好运行的进程 | 调度器从这里选择下一个运行的进程 |
| 设备队列 | 等待特定I/O设备的进程 | 每个设备可以有一条自己的等待队列 |
作业队列包含尚未装入内存的进程;进程被装入内存后进入就绪队列,运行中请求I/O时转入对应设备的队列,I/O完成后再回到就绪队列。调度器操作的主要是就绪队列。
调度算法
先来先服务(FCFS)
最简单的调度算法,采用非抢占式策略。CPU按进程请求的顺序分配,像超市排队结账:一旦进程获得CPU,它就一直运行到完成或发生I/O阻塞。
- 优点:算法简单,容易理解和实现;对到达时间相同的进程按先后顺序处理,是公平的。
- 缺点:如果先运行的是一个长进程,后面的短进程都必须等待,平均等待时间变长,CPU和I/O设备的利用率下降,这种现象称为护航效应。FCFS也无法保证分时系统需要的响应时间。
短作业优先(SJF)
优先调度下一个CPU执行周期最短的进程。CPU执行周期指进程一次连续占用CPU的时间,下文也直接称为CPU执行时间。SJF可以是抢占式的,此时称为最短剩余时间优先;也可以是非抢占式的。
- 优点:在所有进程同时到达的情况下,SJF能给出最小的平均等待时间。
- 缺点:下一个CPU执行周期的长度难以准确预知,通常只能根据历史数据做指数平均预测;如果系统中不断有短进程到来,长进程可能永远得不到执行,形成饥饿。
轮转调度(RR)
为分时系统设计的抢占式算法。系统定义一个时间片,即CPU一次分配给进程连续运行的时间,通常为10–100 ms;就绪队列被视为循环队列,CPU轮流为每个进程服务一个时间片。
- 优点:每个进程都能在有限时间内获得CPU,响应时间短,适合交互式系统;没有进程会连续占用CPU太久。
- 缺点:时间片太短会让上下文切换过于频繁,切换开销吃掉大量CPU时间;时间片长到超过大多数进程的CPU执行时间时,进程在一次时间片内就运行完毕,算法退化为FCFS。
优先级调度
为每个进程分配一个优先级,CPU总是分配给优先级最高的进程。优先级可以在创建时静态确定,也可以在运行时动态调整。
- 优点:可以根据任务的重要性、紧迫程度灵活安排执行顺序。
- 缺点:低优先级的进程可能无限期等待,形成饥饿。常用的缓解办法是老化:随着等待时间增加,逐步提高进程的优先级。
比较
| 算法 | 抢占方式 | 饥饿风险 | 典型场景 |
|---|---|---|---|
| FCFS | 非抢占 | 一般没有 | 批处理、实现简单的场景 |
| SJF | 可抢占或非抢占 | 有,长进程可能饥饿 | 执行时间已知或可预测的批处理 |
| RR | 抢占(按时间片) | 没有 | 分时系统、交互式系统 |
| 优先级 | 可抢占或非抢占 | 有,低优先级进程可能饥饿 | 需要区分任务紧迫程度的系统 |
比较调度算法时,可以按下面的步骤算出一组进程的平均等待时间。
-
画时间轴
按调度顺序标出每个进程实际占用CPU的区间,遇到I/O阻塞时留出空档。
-
求完成时间
记下每个进程最后一次执行结束的时刻,这就是它的完成时间。
-
算等待时间
不计调度开销时,用完成时间减去到达时间、CPU执行时间和阻塞等待时间,得到在就绪队列中等待的总时间。若进程从不阻塞,才可以直接用完成时间减到达时间和CPU执行时间。
-
比较平均值与极端情况
求所有进程等待时间的平均值,同时看最长等待时间和响应时间。平均值小不代表每个进程都及时,交互式系统还要看最坏情况。
例子
FCFS与SJF的平均等待时间
三个进程P1、P2、P3都在0时刻到达,CPU执行时间分别为24、3、3。
按FCFS的顺序P1 → P2 → P3执行:
| 进程 | 等待时间 |
|---|---|
| P1 | 0 |
| P2 | 24 |
| P3 | 27 |
| 平均 | 17 |
按SJF的顺序P2 → P3 → P1执行:
| 进程 | 等待时间 |
|---|---|
| P1 | 6 |
| P2 | 0 |
| P3 | 3 |
| 平均 | 3 |
只改变了执行顺序,平均等待时间就从17降到3。SJF的代价是必须先知道每个进程要执行多久;真实系统只能预测,预测不准时这个最优性就不再成立。
轮转调度的时间片与响应
同样三个进程,P1、P2、P3都在0时刻到达,CPU执行时间分别为24、3、3,时间片取4。
| 进程 | 完成时间 | 等待时间 |
|---|---|---|
| P1 | 30 | 6 |
| P2 | 7 | 4 |
| P3 | 10 | 7 |
| 平均 | — | 约5.67 |
P2、P3都只用一个时间片就完成,不必等P1的24个时间单位全部跑完,响应时间比FCFS短;P1则被切成6段执行。时间片取得越小,短进程响应越快,但切换次数和开销也越大;取得越大,行为越接近FCFS。
交互探索
比较同一组进程在先来先服务和轮转调度下的执行顺序与等待时间。
先来先服务和轮转怎样分配CPU?
比较同一组进程在两种调度策略下的执行顺序与等待时间。
正在准备演示…
练习
FCFS采用哪种调度策略?
参考解答
FCFS是非抢占式的先来先服务:进程按请求顺序获得CPU,一旦开始就运行到完成或主动阻塞。
护航效应描述的是什么现象?
参考解答
护航效应是FCFS的典型问题:一个长进程挡在前面,后面一批短进程只能排队,CPU与I/O设备的利用率也随之下降。短进程导致长进程饥饿是SJF的问题。
SJF的平均等待时间最短这一结论,在下列哪个前提下成立?
参考解答
SJF的最优性建立在“所有进程都在0时刻到达且执行时间已知”之上;真实系统需要预测执行时间,预测误差会让最优性失效。
轮转调度中时间片过短的主要后果是什么?
参考解答
时间片越短,单位时间内切换次数越多,保存和恢复现场的开销越大。时间片过长才会退化为FCFS;饥饿是SJF和优先级调度的问题。
优先级调度中引入老化(aging)是为了解决什么问题?
参考解答
老化随着等待时间增加逐步提高进程的优先级,使低优先级进程最终也能获得CPU,从而缓解饥饿。
三个进程同时到达,CPU执行时间分别为24、3、3。
按FCFS调度(P1 → P2 → P3),平均等待时间是 。
参考解答
P1等待0,P2等待24,P3等待27,平均为
(0 + 24 + 27) / 3 = 17。按SJF调度(P2 → P3 → P1),平均等待时间是 。
参考解答
P2等待0,P3等待3,P1等待6,平均为
(0 + 3 + 6) / 3 = 3。