1.概述
在一个多道程序系统中,进程的数量往往多于处理机的个数,这就不可避免的出现进程争用处理机的情况。处理机调度是对处理机进行分配,即从就绪队列中按照一定的调度算法选择一个进程并将处理机分配给它运行,以实现程序的并发执行。
2.调度的层次
一个作业从提交开始直到完成,需要经历高级调度、中级调度、低级调度这三级调度。
2.1 高级调度(作业调度)
- 按一定原则从外存从后备队列中的作业挑选一个,给它分配内存、I/O设备等必要的资源,并建立相应的进程,以使它们获得竞争处理机的权利。
- 作业调度就是内存与辅存之间的调度。
- 每个作业只调入一次,调出一次。
- 多道批处理系统中大多配有作业调度,其他系统中通常不需要配置作业调度。
2.2 中级调度(内存调度)
引入中级调度的目的:提高内存利用率&系统吞吐量。
中级调度会将那些在内存中但尚且不能运行的进程调至辅存等待并将它们的状态置为挂起态,待内存稍有空闲或者这些进程具备运行条件时,再将它们调进内存,并修改状态为就绪态,挂在就绪队列上等待。
2.3 低级调度(进程调度)
- 从就绪队列中挑选出一个进程,将处理机分配给它运行。
- 进程调度是最基本的一种调度,所有OS都必须配置进程调度。
- 进程调度的频率很高,一般几十ms调度一次。
三级调度的联系:
作业调度为进程活动做准备,进程调度使进程正常活动起来。
内存调度将暂时不能运行的进程挂起,内存调度介于作业调度与进程调度之间。
作业调度次数少,内存调度次数略多,进程调度次数最多。
进程调度是最基本的,不可或缺的。
3.调度的指标
3.1 CPU利用率
3.2 系统吞吐量
- 系统吞吐量是指单位时间内CPU完成的作业的数量。
- 长作业需要消耗较长的处理机时间,因此会降低系统吞吐量;短作业则与之相反。
3.3 周转时间
周转时间是指从作业提交到作业完成所经历的时间,包括作业等待时延、在就绪队列中的排队时延、在处理机上进行I/O操作所消耗的时间…的时间总和。
平均周转时间:
带权周转时间:
平均带权周转时间:
3.4 等待时间
指进程处于等待处理机的时间总和。等待时间越长,用户满意度越低。
调度算法只会影响作业在就绪队列的等待时间。因此,衡量一个算法的优劣,常常仅需要考察其作业的等待时间即可。
3.5 响应时间
指从用户提交请求到系统首次产生响应所需要的时间。
在交互式系统中,往往将作业的响应时间作为衡量调度算法优劣的重要准则之一,站在用户角度上考量,应该尽量降低作业的响应时间,使响应时间处在用户能接受的范围之中。
4.调度的实现
4.1 调度程序(调度器)
4.1.1 概述
- 用于调度和分配CPU的组件称为调度程序(Dispatcher)。
- 调度程序是OS的内核程序。
4.1.2 结构
- 排队器:将系统中的所有就绪进程按照一定的调度算法排除一个或多个就绪队列以供分派器选择。每当有一个进程处于就绪态时,排队器便将它插入相应的就绪队列中去。
- 分派器:依据调度程序所选择的进程,将其从就绪队列中取出,并将CPU分配给该进程。
- 上下文切换器:在对处理机执行进程切换操作时,会发生两对上下文的切换操作:第一对:将当前进程的上下文保存到其PCB中,调入分派程序的上下文。第二对:调出分派程序的上下文,将新进程的上下文调入(即将新进程的CPU现场信息装入处理机的各个相应的寄存器组)。
进行上下午切换时,可能需要执行大量的load和store指令来存取寄存器的内容,这会带来较大的开销,现在通常采用硬件实现的方法来降低开销,通常采用两组寄存器,一组供内核使用,一组供用户使用,这样,进行上下文切换时,只需要改变指针指向,让其指向当前寄存器组即可。
4.2 调度的时机与切换
理论上:请求调度的时间发生后,才可能运行调度程序,调度了新的就绪进程后,才会进行进程切换。
不能进行进程调度与切换的情况:
- 处在中断过程中。由于中断过程较为复杂,在实现上很难做到进程切换,且中断处理是系统工作的一部分,逻辑上不属于某一进程,不应被剥夺处理机资源。
- 处在OS内核临界区中。进入临界区后,需要进行独占式访问,因此需要加锁以防止其他并行进程的进入,这也要求在解锁前不能进行进程的切换,这样做也能够加快临界区的释放。
- 其他需要完全屏蔽中断的原子操作过程中。在原子操作过程中,连中断都需要屏蔽,更别说更低一级的进程切换了。。。
应该进行进程调度与切换的情况:
- 发生引起调度条件且当前进程无法继续运行下去时。(非剥夺式调度)
- 中断处理结束或自陷处理结束后,返回被中断进程的用户态执行现场前,若置上请求调度标志,即可马上进行进程的调度与切换。(剥夺式调度)
4.3 调度的过程
进程切换往往在进程调度完成后发生,它需要保存当前进程当前断点处的现场信息,恢复被调度进程的现场信息。
上下文切换
上下文切换:切换CPU到另一个进程需要保存当前进程的状态并恢复另一个进程的状态。
上下文:某一时刻的CPU寄存器和PC的内容。
过程
- 挂起当前进程,保存其CPU上下文信息(包括CPU寄存器&PC)。
- 更新当前进程的PCB。
- 将当前进程的PCB移入其他队列,如就绪队列或等待某一事件的阻塞队列。
- 选择新进程运行,并更新其PCB。
- 跳转到新进程的PCB中的PC指向的位置执行。
- 恢复处理机的上下文。
切换开销
每秒几十次甚至上百次的切换,每次切换需要纳秒级的时间,上下文切换对系统来说是开销巨大的。(现在采用硬件解决该问题,比如提供多个寄存器组,这样上下文切换时只需要改变寄存器组的指针指向即可)
上下文切换&模式切换
- 上下文切换:只发生在内核态,它是多任务OS中的一个必需的特性。
- 模式切换:CPU逻辑上可能还在执行同一个进程,只不过用户态进程最初运行在用户态,进程可能因中断或异常进入核心态运行,执行完后又回到用户态中断处继续运行。
调度&切换
- 调度是指决定资源分配给哪一个进程的行为,是决策行为。
- 切换是指实际分配的行为,是执行行为。
一般来说,先有资源的调度,后有进程的切换。
在进程处于临界区时,可以进行处理机调度。(只要不破坏资源使用的规则)
4.4 调度的方式![](https://i-blog.csdnimg.cn/blog_migrate/1f48ff611b64abf58eceb82e53cc292e.png)
4.4.1 非抢占式/非剥夺式调度
4.4.1.1 概述
当一个进程正在处理机上运行时,若有一个更为重要或紧迫的进程进入就绪队列时,当前进程仍将继续运行,直至执行完成或进入阻塞态时才会让出处理机给其他进程。
4.4.1.2 优点
实现简单,系统开销小,适用于大多数批处理系统。
4.4.1.3 缺点
不适用于分时系统和大多数的实时系统。
4.4.2 抢占式/剥夺式调度
4.4.2.1 概述
当一个进程正在处理机上运行时,若有一个更为重要或紧迫的进程进入就绪队列时,则调度程序可根据某种原则去暂停当前进程的执行,然后将处理机分配给更为重要或紧迫的进程。
4.4.2.2 优点
明显提升了系统吞吐量&响应效率。
“抢占”非任意性行为,其必须遵循一定的原则,如优先级原则、短进程优先原则、时间片原则等。
4.5 闲逛进程(Idle)
- 当系统中无就绪进程时,便会安排闲逛进程运行,若无其他进程就绪,它将一直运行下去。闲逛进程会在运行过程中执行测试中断。
- 闲逛进程的优先级最低,只要有进程就绪,它将立刻让出处理机。
- 闲逛进程不占用任何CPU之外的资源,它不会被阻塞。
4.6 线程的调度
4.6.1 ULT调度
- 由于内核不知道线程的存在,因此内核只能选择一个进程,并对其进行时间控制,由进程中的调度程序来决定哪个线程的运行。
- ULT的切换在同一进程中进行,仅需少量机器指令。
4.6.2 KLT调度
- 由内核来选择哪一个线程运行,通常不会考虑哪个线程属于哪个进程,内核会给予被选择的线程一个时间片,时间片过后将会强制挂起该线程。
- KLT的切换需要完整的上下文切换、修改内存映像、使高速缓存失效,这就会带来较大的延迟。
5.调度算法
5.1 先来先服务(FCFS)
5.1.1 概述
最简单的调度算法,既可用于作业调度,也可以用于进程调度。FCFS会从后备队列中选择最先进入队列的一个或多个作业,将它们调入内存并分配给它们必需的资源,然后创建进程并移入就绪队列中。
5.1.2 优点
- 算法简单。
- 对长作业有利。
- 有利于CPU繁忙型作业。
表明上看,FCFS对所有作业都是公平的,但是若一个长作业先到达系统,则会导致后续到达的作业需要等待很长一段时时间,因此FCFS不能作为分时系统和实时系统的主要调度策略。
CPU繁忙型作业是指一旦占有CPU,则可能会运行很长时间,很少请求I/O操作,类似于长作业。
I/O繁忙型作业是指运行过程中需要频繁请求I/O操作,可能会频繁放弃CPU,所以占用CPU的时间不会太长。
5.2 短作业优先(SJF)
5.2.1 概述
SJF会从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存并分配给它们必需的资源,将处理机分配给它们并立即执行,直到完成或发生某事件二阻塞时才让出处理机。
5.2.2 优点
SJF的平均等待时间和平均周转时间最少。
5.2.3 缺点
- SJF对长作业不利。SJF会导致长作业的周转时间增加,且如果一长作业进入后备队列中后,后续又有短作业进入,而调度程序总是优先调度短作业运行,这就导致长作业可能存在“饥饿”现象。
- SJF完全没有考虑到作业的紧迫程度,因此它无法保证紧迫性作业会被及时处理。
- 由于作业长度是根据用户所提供的预估执行时间而定的,而用户有可能有意无意地缩短其作业的预估运行时间,因此,SJF可能就无法做到真正的短作业优先调度了。
SJF算法可以分为抢占式SJF和非抢占式SJF。
5.3 优先级
5.3.1 概述
优先级调度算法会从后备队列中选择优先级最高的一个或若干个作业,将它们调入内存并分配它们必需的资源,然后创建进程并移入就绪队列中。
在进程调度中,优先级调度算法将每次选择优先级最高的进程,然后将处理机分配给它运行。
5.3.2 分类
5.3.2.1 非抢占式优先级调度算法
当一个进程正在处理机上运行时,即使有个更高优先级的进程进入就绪队列,当前进程依旧继续执行,直至由于其自身原因而让出处理机,才能把处理机分配给就绪队列中的优先级最高的进程。
5.3.2.2 抢占式优先级调度算法
当一个进程正在处理机上运行时,若有个更高优先级的进程进入就绪队列,则将立即暂停正在运行的线程,然后将处理机分配给优先级更高的进程。
进程的优先级分类
**静态优先级**
:优先级在进程创建时确定,且在整个进程运行期间保持不变。静态优先级的主要依据有进程类型、进程对资源的要求、用户要求等。**动态优先级**
:在进程运行过程中,将根据进程情况的变化动态调整优先级。动态优先级的主要依据有进程占用CPU时间的长短、就绪进程等待CPU时间的长短等。
优先级设置原则(参考)
- 系统进程 > 用户进程。
- 交互型进程 > 非交互型进程。(即前台进程 > 后台进程)
- I/O型进程 > 计算型进程。由于I/O设备的处理速度比CPU慢得多,因此应该通过提高其优先级的方式让其尽早开始工作以提供系统的整体效率。
5.4 高响应比优先
5.4.1 概述
是对FCFS和SJF算法的一种平衡。
在每次进行作业调度时,会先计算出每个作业的响应比,然后从中选择出响应比最高的作业投入运行。
5.4.2 优点
对于长作业,其作业响应比可随等待时间的增加而增加,当其等待时间足够长时,也可以获得处理机,从而克服了“饥饿”现象。
5.5 时间片轮转
5.5.1 概述
该算法中,系统将所有就绪进程按FCFS排成一个就绪队列,然后总是选择其中的第一个进程开始执行,每次执行仅能执行一个时间片的时间,时间片占用完后,即使该进程没有执行完,也需要让出处理机给下一个就绪进程,然后当前线程将返回到就绪队列的队尾,等待下一次的运行。
5.5.2 评估
该算法适用于分时系统。
时间片划分的大小对系统的开销影响巨大。若划分足够的大,则该算法将退化为FCFS,=; 若划分的很小,则处理机将在进程间进行频繁的切换,使处理机开销过大,系统吞吐量降低。因此时间片大小选择应适中。时间片的长短主要受系统的响应时间、就绪队列中的进程数目和系统的处理能力这几个因素的影响。
时间片轮转调度算法是为了多个用户能及时干预系统。
时间片轮转调度算法绝对是可抢占的,因为它是由时间配额决定的。
5.6 多级队列
5.6.1 概述
该算法会在系统中设置多个就绪队列,将不同类型或性质的进程固定分配到不同的就绪队列中去。每个就绪队列将采用不同的调度算法。同一队列中的进程可以设置不同的优先级,不同的队列本身也可以设置优先级。
在多处理机系统中,可以为每个处理机设置一个单独的就绪队列,然后每个处理机就可以实施各自不同的调度策略。
5.7 多级反馈队列
5.7.1 概述
- 该算法也需要设置多个就绪队列,并为每个就绪队列赋予不同的优先级。第一级队列的优先级最高,第二级队列次之,后续队列的优先级依次降低。
- 赋予给各个队列的进程运行所需的时间片大小也不相同。优先级越高的队列,其时间片越小。
- 每个队列采用FCFS算法。新产生的就绪进程将首先进入第一级队列,然后进行时间片轮转调度,直到该进程执行到其时间片用完,若时间片用完后,该进程没能执行完毕,于是它将被移入第二级队列中重复本步的前面的过程,若依旧没执行完毕,则继续转到下一级队列中,如此反复,当该进程被移入到最后一级队列中时,将参与时间片轮转调度(即使一次执行也没能执行完毕),直至该进程执行完毕。
- 总体上,按队列优先级进行调度,当且仅当第一级就绪队列空时,调度程序才会调度第二级队列,以此类推。若在第n级队列调度过程中,有更高优先级的进程进入时,该进程将被自动移入当前队列的末尾,然后将处理机分配给新到的这个进程运行。
5.7.2 评估
- 是时间片轮转调度算法&优先级调度算法的ProMax版,也是前面算法的究极融合增强版。
- 对于终端型作业用户,该算法满足其短作业优先的需求。
- 对于短批处理作业用户,该算法使得作业周转时间较短。
- 对于长批处理作业用户,该算法能够使长作业经前面几个作业得到部分执行,不会使其长时间得不到处理。
调度算法的比较: