一、调度的基本概念
当有一堆任务要处理,但由于资源有限而无法同时处理。这是需要确定以某种规则来决定处理这些任务的顺序,这就是“调度”所研究的问题。调度可以分为三个层次,分别是高级调度(作业调度),中级调度(内存调度)以及低级调度(进程调度)。其中:高级调度是外存与内存之间的调度,每个作业只调入一次、调出一次,作业调入与调出时创建或者撤消相应的 PCB。中级调度则是决定将哪个处于挂起状态的进程重新调入内存。而低级调度的主要任务是按照某种方法和策略从就绪队列中选取一个进程,将处理机分配给它。
调度类别 | 要做什么 | 调度发生时刻 | 发生频率 | 对进程状态的影响 |
---|---|---|---|---|
高级调度(作业调度) | 按照某种规则,从后备队列中选择合适的作业将其调入内存,并为其创建进程 | 外存→内存(面向作业) | 最低 | 无→创建态→就绪态 |
中级调度(内存调度) | 按照某种规则,从挂起队列中选择合适的进程将其数据调回内存 | 外存→内存(面向进程) | 中等 | 挂起态→就绪态(阻塞挂起→阻塞态) |
低级调度(进程调度) | 按照某种规则,从就绪队列中选择一个进程为其分配处理机 | 内存→CPU | 最高 | 就绪态→运行态 |
二、进程调度的切换与过程
1. 进程调度的时机
1.1 需要进行进程调度与切换的情况
- 当前进进程主动放弃处理机:
- 进程正常终止
- 运行过程中发生异常而终止
- 进程主动请求阻塞(如 等待I/O)
- 当前运行的进程被动放弃处理机:
- 分给进程的时间片用完
- 有更紧急的事需要处理(如 I/O中断)
- 有更高优先级的进程进入就绪队列
1.2 不能进行进程调度与切换的情况
- 在处理中断的过程中。中断处理过程复杂,与硬件密切相关,很难做到在中断处理过程中进行进程切换。
- 进程在操作系统内核程序临界区中。
- 在原子操作过程中(原语)。原子操作不可中断,要一气呵成(如之前提到的修改 PCB 中进程状态标志,并把 PCB 放到相应队列)
2. 进程调度的方式
2.1 非剥夺调度方式
非剥夺调度方式,又称非抢占方式。即,只允许进程主动发起处理器。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,知道该进程终止或主动要求进入阻塞态。其实现很简单,系统开销小但是无法及时处理紧急任务,适合于早期的批处理系统。
2.2 剥夺调度方式
剥夺调度方式,又称抢占方式。当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要更紧迫的那个进程。这种方式可以优先处理更紧急的进程,也可实现让各进程按时间片轮流执行的功能(通过时钟中断)。适合于分时操作系统、实时操作系统。
3. 进程调度与进程切换
“狭义的进程调度”与“进程切换”的区别:狭义的进程调度指的是从就绪队列中选中一个要运行的进程。(这个进程可以是刚刚被暂停执行的进程,也可以是另一个进程,后一种情况就需要进程切换);进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程;广义的进程调度包含了选择一个进程和进程切换两个步骤。
进程切换的过程主要完成了:
- 对原来运行进程各种数据的保存
- 对新的进程各种数据的恢复(如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块)
注意:进程切换是有代价的,因此如果过于频繁地进行进程调度、切换,必然会使整个系统的效率降低,使系统大部分时间都花在了进程的切换上,而真正用于执行进程的时间减少。
三、调度算法
不同环境的调度算法不同,因此需要针对不同环境来讨论调度算法。
1. 调度算法的评价标准
2. 批处理系统
2.1 先来先服务 first-come first-serviced(FCFS)
非抢占式的调度算法,按照请求的顺序进行调度。该算法即用于进程调度,有用于作业调度。该算法不会导致饥饿(饥饿即某进程/作业长期得不到服务)。有利于长作业,但不利于短作业,因为短作业必须等待前面的长作业执行完毕后才能执行,而长作业又需要执行很长的时间,造成了短作业等待时间过长。
2.2 短作业优先 shortest job first(SJF)
非抢占式的调度算法,按估计运行时间最短的顺序进行调度。即可用于作业调度,也可用于进程调度(SPF)。长作业有可能会饿死,处于一直等待作业短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。
2.3 最短剩余时间优先 Shortest Remaining Time Next(SRTN)
最段作业优先的抢占式版本,按剩余运行时间的顺序进行调度。当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较。如果新的进程需要的时间最少,则挂起当前进程,运行新的进程。否则新的进程等待。
2.4 高响应比优先 Highest Response Ratio Next(HRRN)
非抢占式算法,在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务:
响
应
比
=
等
待
时
间
+
要
求
服
务
时
间
要
求
服
务
时
间
≥
1
响应比=\frac{等待时间 + 要求服务时间}{要求服务时间} \geq 1
响应比=要求服务时间等待时间+要求服务时间≥1
综合考虑了等待时间和运行时间(要求服务时间)。等待时间相同时,要求服务的时间短的优先(SJF的优点);要求服务时间相同时,等待时间长的优先(FCFS的优点)。对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题。
3. 交互式系统
交互式系统有大量的用户交操作,在该系统中调度算法的目标是快速地进行响应。
3.1 时间片轮转调度算法(RR)
将所有就绪进程按FCFS
的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。
时间片轮转算法的效率和时间片的大小有很大关系:
- 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程上就会花过多时间。
- 而如果时间片太长,那么实时性就不能得到保证。甚至退化为
FCFS
。
3.2 优先级调度算法
为每个进程分配一个优先级,按优先级进行调度。为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。
3.3 多级反馈调度算法
一个进程需要执行 100 个时间片,如果采用时间片轮转调度算法,那么需要交换 100 次。
多级队列是为这种需要连续执行多个时间片的进程考虑,它设置了多个队列,每个队列时间片大小都不同,例如 1,2,4,8,…。进程在第一个队列没执行完,就会被移到下一个队列。这种方式下,之前的进程只需要交换 7 次。每个队列优先权也不同,最上面的优先权最高。因此只有上一个队列没有进程在排队,才能调度当前队列上的进程。可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。