概述
对于单处理器系统,CPU只能执行一个进程,其他进程必须等待,直到CPU空闲为止。多道程序的目标是为了使任何时候都有进程在执行,使CPU的利用率最大化。
CPU调度使进程在等待时(通常是等待某些IO请求完成),从该进程拿走CPU的使用权交给另一个进程,如此循环往复。
CPU-IO区间周期
进程有两个属性:CPU执行,I/O等待周期,这是CPU成功调度依赖的基础。进程执行从CPU区间(CPU burst)开始,之后到I/O区间(IO burst),循环往复,最后一个操作也是在CPU区间(通过系统请求终止执行)。
CPU区间的长度通过大量的测试,得到一个进程通常是有大量的短CPU区间和少量长CPU区间,这种分布有助于选择合适的CPU调度算法。
CPU调度程序
在CPU空闲时,操作系统从就绪队列中选择一个进程来执行,这一操作通常由短期调度程序或CPU调度程序执行
就绪队列可以有多种实现(FIFO、优先队列,树,无序链表…),不过从概念上来说,就绪队列中的所有队列都要排队等待,队列中的记录通常为PCB。
CPU调度决策通常会在以下四种环境中发生:
- 一个进程从运行状态切换到等待状态(如IO请求,系统调用wait() )
- 一个进程从运行状态切换到就绪状态(如中断)
- 一个进程从等待状态切换到就绪状态(如IO请求完成)
- 一个进程终止时
对于第1和第4种情况,没有选择只有调度。一个新进程(如果有)必须被选择执行,这种情况下的调度方案称作非抢占的(nonpreemptive)或协作的(coorperative)。
对于其他情况(包括但不限于第2和第3种),可以进行选择,这种情况下该调度方案为抢占的(preemptive)。
分派程序
分派程序(dispatcher)是一个模块,是与CPU调度功能有关的另一个部分,有以下功能:
- 切换上下文
- 切换到用户模式
- 跳转到用户程序的合适位置,以重新启动程序
分派程序在每次切换的时候都会调用(所以应该尽可能的快),分派程序停止一个进程而启动另一个进程花费的时间成为分派延迟(dispatch latency)
调度准则
不同的CPU调度算法可能适用于不同的进程,为了比较各个CPU的调度算法,提出了以下准则:
- CPU使用率:CPU应该尽可能忙,对于真实系统,CPU使用率一般在40%~90%(需要最大化)
- 吞吐量:一个时间单元内完成进程的数量(需要最大化)
- 周转时间:从进程提交到进程完成的时间段(需要最小化)
- 等待时间:为在就绪队列中等待所花费的时间之和(需要最小化)
- 响应时间:从提交请求到产生第一响应的时间(需要最小化)
这些调度准则不能全部满足,在满足一项准则的时候,可能会有另一项准则收到损失,如:
- CPU利用率和响应时间:上下文切换时CPU是空闲的,因此当上下文切换的次数减少到时,CPU利用率增加,但这样可能会导致某个进程响应时间的增加。
- 平均周转时间和最大等待时间:最先执行最短任务可以减小周转时间,但这样一个长时的任务的等待时间就会增加
- I/O设备利用率和CPU利用率: CPU利用率的最大化可以通过减少上下文切换实现。而I/O设备利用率的最大化则是通过尽可能调度已经准备好进行I/O操作的任务,这会导致上下文切换 。
调度算法
在说明调度算法之前,需要再回顾一下就绪队列:就绪队列包含了系统中,驻留在内存中就绪的,准备运行的进程。该队列通常用链表实现,头结点指向第一个和最后一个PCB块的指针,每个PCB块包括指向下一个PCB的指针域。
先到先服务算法
先到先服务算法(first come, first served(FCFS)),即简单的FIFO队列,先请求CPU的进程先分配到CPU,但平均等待时间较长,并会因为等待一个CPU约束进程很多IO约束进程无法执行而产生护航效果(convoy effect)
该算法是非抢占的
最短作业优先调度
最短作业优先调度(shortest-job-first(sjf))将每个进程与下一个CPU区间段相关联,当CPU空闲时,会赋给具有最短下一个CPU区间的进程,如果两个进程区间相同,则采用FCFS调度处理。
这个算法是最佳的,但一个难点在于如何知道下一个CPU区间的长度,因此该算法经常用于长期调度,通过长期对某个进程的一个CPU区间的指数平均值来判断该进程下一个CPU区间的长度。(也因此改算法无法用于短期CPU调度上)
该算法可能是抢占的或非抢占的,抢占sjf(也称为最短剩余时间优先调度(shortest-remainint-time-first scheduling))可以抢占当前运行的进程,非抢占sjf会允许当前进程完成其CPU区间。
指数平均值:
θn+1 = atn + (1-a)θn
t是当前信息,θ是历史信息,a来控制权重,一个常见的值是1/2
优先级调度
优先级调度算法(priority scheduling algorithm)中,每一个进程都有一个与它相关联的优先级,优先级最高的任务会被分配到CPU,具有相同优先级的任务按FCFS调度。
sjf是优先级调度算法的一个特例。其优先级为下一个(预测的)CPU区间的倒数,CPU区间越大,优先级越小。
优先级通常为固定区间的数字,如0~7,0~4095,
不同的系统中,采用高数字高优先和低数字高优先都是可能的。
优先级的定义方式有两种,外部定义/内部定义
- 内部定义优先级(internally defined priority)使用一些测量数据计算进程优先级,如时间极限,内存需求,打开文件的数量,IO请求的多少等
- 外部优先级(external priorities )是通过操作系统之外的准则定义的,包括进程重要性,费用,政治因素等
如sjf算法中的抢占与非抢占一样,优先级调度算法同样有抢占和非抢占的问题。抢占优先级调度算法会抢占CPU,非抢占优先级调度算法会将新进程添加到就绪队列的头部。
该算法的一个主要问题:无穷阻塞(indefinite blocking)/饥饿(starvation),因为优先级调度算法会导致低优先级进程无穷等待CPU。其解决方法之一是老化(aging),即逐渐增加在系统中等待时间很长的进程的优先级。
转轮法调度
转轮法调度(round-robin RR)调度算法专门为分时系统设计。其与FCFS相似,但增加了抢占以切换进程。
其实现思想是:定义一个较小的时间单元/时间片(10-100ms),每一个进程分配不超过一个时间单元的CPU,时间结束后,该进程会通过中断被添加到就绪队列的尾部(如果该进程没有完成任务)
在性能表现上,如果时间片较大,那么其性能接近FCFS,如果时间片较小,那么该算法会造成大量的上下文切换,因此时间片相对于上下文切换的时间来说必须足够大。
现在来假设转轮法调度的时间片时间为10ms,有10个IO约束的进程,每执行1msCPU计算执行10ms的IO请求。
问题是:在一个时间片中,一个进程花了1ms完成了CPU计算,该进程是会等待9ms完成这个时间片,还是会直接上下文切换到下一个进程?
算法评估(待补完)
- 分析评估法
- 确定模型法
- 排队模型
- 模拟
- 实现