首页 > 代码库 > 处理器调度

处理器调度

U调度:

即按照一定的的调度算法从就绪队列中选择进程,把CPU使用权交给被选中进程

如果没有就绪队列中没有进程,系统会安排一个系统空闲进程(即什么也不做)idle进程,目的就是让CPU不空闲

 

系统场景:

N(N>=1)个进程处于就绪队列中,M(M>=1)个CPU给哪个进程分配哪个CPU?怎么分配?(调度算法),什么时候分配?(调度时机),怎么让进程上CPU?(调度过程,涉及到上下文的保存

 

调度时机:

进程正常终止 或 由于某种错误而终止

新进程创建 或 一个等待进程变成就绪

当一个进程从运行态进入阻塞态     

当一个进程从运行态变为就绪态

前两种是CPU上有进程,后两种是CPU上没有进程执行时发生调度

总之往往是内核对中断/异常/系统调用处理后返回到用户态时发生调度。

 

调度过程:

进程切换:是指一个进程让出处理器,由另一个进程占用处理器的过程

进程切换主要包括两部分工作:
1.切换全局页目录以加载一个新的地址空间
2.切换内核栈(因为进程地址空间发生变化)硬件上下文,其中硬件上下文包括了内核执行新进程需要的全部信息,如CPU相关寄存器

总之切换过程包括了对原来运行进程各种状态的保存对新的进程各种状态的恢复

 

例如:

进程A下CPU,进程B上CPU

此时上下文保存的具体步骤为:

1.保存进程A的上下文环境(程序计数器、程序状态字、其他寄存器……)
2.用新状态和其他相关信息更新进程A的PCB
3.把进程A移至合适的队列(就绪、阻塞……)
4.将进程B的状态设置为运行态
5.从进程B的PCB中恢复上下文(程序计数器 、程序状态字、其他寄存器……)

 

但是频繁进程切换就会涉及到上下文切换的开销:

直接开销:

1.保存和恢复寄存器

2.切换进程地址空间

间接开销:

cache失效,缓冲区的缓存失效,TLB失效

 

 

调度算法:

技术分享

以此为设计算法的出发点。

 

调度算法衡量指标:

吞吐量 Throughput: 每单位时间完成的进程数目

周转时间TT(Turnaround Time):每个进程从提出请求到运行完成的时间

响应时间RT(Response Time):从提出请求到第一次回应的时间

CPU 利用率(CPU Utilization):CPU做有效工作的时间比例

等待时间(Waiting time):每个进程在就绪队列(ready queue)中等待的时间

 

调度算法要点:

进程优先数与优先级并不成正相关:基本上优先数越小优先级越大

进程优先级可以分成静态和动态的:

静态优先级:
进程创建时指定,运行过程中不再改变
动态优先级:
进程创建时指定了一个优先级,运行过程中可以动态变化
如:等待时间较长的进程可提升其优先级(windows中对饥饿线程的做法)

 

根据不同的优先级就设计不同就绪队列的组织方式:

技术分享

就绪队列从上到下优先级(静态,从创建就分配好了进入对应的就绪队列中)逐渐降低,每次操作系统从就绪队列1中选择进程上CPU,若队列1位空则选择下一级队列中进程,以此类推。

技术分享

从上到下进程优先级也是逐渐降低,但是进程一创建就进入高优先级的就绪队列1,但是随着进程不断地用完分配给它的时间片,他的优先级会动态地降低(Unix BSD系统)

 

进程抢占与非抢占:

可抢占式Preemptive(可剥夺式)
当有比正在运行的进程优先级更高的进程就绪时,系统可强行剥夺正在运行进程的CPU,提供给具有更高优先级的进程使用

不可抢占式Non-preemptive(不可剥夺式 )
某一进程被调度运行后,除非由于它自身终止,否则一直运行下去

 

 I/O密集型与CPU密集型:

 I/O密集型:进程大量时间都是用在等待I/O设备上

技术分享

CPU密集型:

需要大量的CPU时间来进行计算

技术分享

 

时间片:

分配给调度上CPU的进程,确定了允许该进程运行的时间长度

 

 

调度算法:

 

批处理的调度算法:

先来先服务(First Come First Serve):

思想:按照进程就绪的先后顺序使用CPU(非抢占式)

优缺点:

公平,易实现,但是对于运行时间长的进程后面的短进程不利

 

例子:

三个进程按顺序就绪:P1、P2、P3,进程P1执行需要24s,P2和P3各需要3s

FCFS算法:  

技术分享

吞吐量:3 jobs/ 30s = 0.1 jobs/s

周转时间TT(从提交到运行完成时间):P1:24;P2:27;P3:30

平均周转时间:(24+27+30)/ 3 = 27s

但是不同的顺序状态会影响周转时间

按照P2,P3,P1就绪的话:

技术分享

吞吐量:3 jobs/ 30s = 0.1 jobs/s

周转时间TT:P1:30;P2:3;P3:6;

平均周转时间:13s

 

 

短作业优先(Shortest Job First):

思想:具有最短完成时间的进程优先执行(非抢占式)

 

最短剩余时间优先(Shortest Remaining Time Next):

思想:(SJF抢占版)

当一个新就绪的进程比当前运行进程具有更短的完成时间时,新就绪进程会抢占CPU执行

 

例子:

技术分享

对于非抢占式短作业优先:

首先0时刻,P1先进入,所以P1先执行,之后P2,P3,P4都会进入,但由于不是抢占式,所以就在就绪队列中等待,之后P1执行完成,从就绪队列中选择运行时间短的P3上CPU执行,之后又按到达先后,选择P2,P4执行

对于抢占式短作业优先:

首先0时刻,P1进入,所以P1先执行,但是到了2时刻时,就绪队列中进来P2,它的完成时间为4小于P1完成时间的5,所以CPU被抢占,P2执行,但是到了4时刻时,P3进入就绪队列,P3完成时间1小于P2完成时间2,所以CPU被抢占,P3执行,之后P4进入就绪队列,此时P3也执行完毕,从就绪队列中选择完成时间最短的上CPU,选择P2,剩余2运行时间,等到P2执行完时,P4完成时间4小于P1完成时间5,所以P4上CPU,之后P5上CPU

 

优缺点
最短的平均周转时间
但是当短任务很多时,可能使长的任务长时间得不到运行最终产生 “饥饿”现象 (starvation)

 

最高相应优先比(Highest Response Ratio Next)

设计思想:

调度时,首先计算每个进程的响应比R之后,总是选择 R 最高的进程执行

响应比R = 周转时间 / 处理时间 =(处理时间 + 等待时间)/ 处理时间 = 1 +(等待时间 / 处理时间)PS:处理时间(完成所需时间),等待时间(在就绪队列中等待的时间)

随着等待时间的增加,R会增大从而有更大机会上CPU

 

缺点:每次都需计算R值开销较大

 

交互式系统的调度算法:

时间片轮转调度:

目标:改善短进程的平均响应时间

解决问题的思路
1.周期性切换
2.每个进程分配一个时间片
3.时间片用完产生时钟中断从而达到轮换

技术分享

当B进程用完时间片后(此时B进程可能还没有完全执行完),B进程从运行态到就绪态,并将对应的PCB插到就绪状态队列队尾位置

 

时间片大小的确定:

技术分享

太长 --大于典型的交互时间
1.降级为先来先服务算法
2.延长短进程的响应时间

若太长,那么每个进程就完全被执行完成,接着换下一个进程,这就退化成了FCFS算法,同时因为降为FCFS导致短进程若排在长进程之后,其响应时间将增长。

 技术分享

太短 --小于典型的交互时间
  进程切换浪费CPU时间

太短,那么大部分CPU时间将浪费在调度上 

优缺点
公平

有利于交互式计算,响应时间快

由于进程切换,时间片轮转算法要花费较高的开销

RR对不同大小的进程是有利的,但是对于相同大小的进程反而不利 例如:

两个进程A、B,运行时间均为100ms
?时间片大小为1ms
?上下文切换不耗时
如果使用时间片轮转(RR)算法的平均周转时间?

ABABABAB…… …… …… ……A(199)B(200)

A周转时间为199ms   B周转时间为200ms   平均周转时间为199.5ms 

使用先来先服务(FCFS)算法呢?

A周转时间为100ms,B周转时间为等待A完成100 + 自己运行时间100 = 200ms,平均周转时间为150ms

 

虚拟轮转调度算法:

技术分享

对于I/O密集型进程来讲,可能它在CPU上运行的时间很短,基本上都在等待I/O操作,这可能让分配给该进程的时间片都没有用完,该进程就进入就绪队列中,这就对I/O密集型进程不合理。所以就增加一个辅助队列和多个I/O事件所对应的队列。I/O密集型进程用完时间片后就进入对应I/O队列中,然后由I/O队列添加到辅助队列中,CPU先从辅助队列中选取进程上CPU,因为这些进程只占用CPU很少时间,再从就绪队列中挑取其他进程。

 

最高优先级调度算法:

设计思想:选择优先级最高的进程投入运行

通常:系统进程优先级 高于 用户进程
     前台进程优先级 高于 后台进程
   操作系统更偏好 I/O型进程

缺点:

会产生饥饿现象,低优先级在大量高优先级进程中始终得不到运行,而且会出现优先级反转问题:

一个低优先级进程持有一个高优先级进程所需要的资源,使得高优先级进程等待低优先级进程运行

例如:

设H是高优先级进程,L是低优先级进程, M是中优先级进程(CPU密集型)
场景:L进入临界区执行,之后被H抢占;
   H也要进入临界区,失败,因为所需资源被低优先级占有,从而被阻塞;
   M上CPU执行,L因优先级较低无法执行,所以H也无法执行

解决方案
1.设置优先级上限(进入临界区进程优先级为最高)
2.优先级继承(如果某个低优先级进程限制了高优先级进程,那么该低优先级将继承高优先级)
3.使用中断禁止(进入临界区后禁止因为优先级高低而产生中断)

 

多级反馈队列调度算法:

设计思想:

1.设置多个就绪队列,第一级队列优先级最高
2.给不同就绪队列中的进程分配长度不同的时间片第一级队列时间片最小;随着队列优先级别的降低,时间片增大(为了平衡优先级和时间片的关系)
3.当第一级队列为空时,在第二级队列调度,以此类推
4.各级队列按照时间片轮转方式 进行调度
5.当一个新创建进程就绪后,进入第一级队列
6.进程用完时间片而放弃CPU,进入下一级就绪队列(该进程优先级降低,CPU密集型进程吃亏)
7.由于阻塞而放弃CPU的进程进入相应的等待队列,一旦等待的事件发生,该进程回到原来一级就绪队列(队首/队尾,要考虑,上CPU后时间片是原来剩余的还是全新的也要考虑)

 

总结:

 技术分享

 

多处理器调度算法:

1.要决定选择哪一个进程执行,还需要决定在哪一个CPU上执行

2.要考虑进程在多个CPU之间迁移时的开销(  高速缓存失效、TLB失效)

3.尽可能使进程总是在同一个CPU上执行

   如果每个进程可以调度到所有CPU上,假如进程上次在CPU1上执行,本次被调度到CPU2,则会增加高速缓存失效、TLB失效;如果每个进程尽量调度到指定的CPU上,各种失效就会减少

4. 考虑负载均衡问题

 

windows调度算法:

调度单位是线程

设计思想:采用基于动态优先级的、抢占式调度,结合时间配额的调整

实现:

1.就绪线程按优先级进入相应队列
2. 系统总是选择优先级最高的就绪线程运行
3. 同一优先级的各线程按时间片轮转进行调度
4. 多CPU系统中允许多个线程并行运行

 

引发线程调度的条件
1.一个线程的优先级改变了
2.一个线程改变(增加了CPU)了它的亲和(Affinity)处理机集合(将线程局限于几个CPU之间运行,这几个CPU就叫亲和处理机集合,当其他处理机空闲该线程也不能被执行)
3.线程正常终止 或 由于某种错误而终止
4.新线程创建 或 一个等待线程变成就绪
5.当一个线程从运行态进入阻塞态
6.当一个线程从运行态变为就绪态

 

 windows线程优先级:

①实时优先级:不改变其优先级

②可变优先级:其优先级可以在一定范围内升高或降低

③系统线程,其中有个零号线程定期用来把空闲页面清零

 

时间配额

1.时间配额不是一个时间长度值,而一个称为配额单位(quantum unit)的整数
2.一个线程用完了自己的时间配额时,如果没有其他相同优先级的线程,Windows将重新给该线程分配一个新的时间配额,让它继续运行

 

调度策略:

1.主动切换

一旦某线程从运行态转到阻塞态,OS就从同优先级就绪队列中选择一个线程上CPU
2.抢占

当线程被抢占时,它被放回相应优先级的就绪队列的队首

 ①处于实时优先级的线程在被抢占时,时间配额被重置为一个完整的时间配额
 ②处于可变优先级的线程在被抢占时,时间配额不变,重新得到CPU后将运行剩余的时间配额

3.时间配额用完

假设线程A的时间配额用完
1.A的优先级没有降低
  ①如果队列中有其他就绪线程,选择下一个线程执行,A回到原来就绪队列末尾
  ②如果队列中没有其他就绪线程,系统给线程A分配一个新的时间配额,让它继续运行

2.A的优先级降低了(降低可能是之前A优先级被提高了),Windows 将选择一个更高优先级的线程

 

Windows的调度策略注意的问题
 如何体现对某类线程具有倾向性?
 如何解决由于调度策略中潜在的不公平性而带来饥饿现象
 如何改善系统吞吐量、响应时间等整体特征?

解决方案:

  提升优先级,给线程分配一个很大的时间配额

 

1.I/O操作完成
2.信号量或事件等待结束
3.前台进程中的线程完成一个等待操作
4.由于窗口活动而唤醒窗口线程
5.线程处于就绪态超过了一定的时间还没有运行—— “饥饿”现象

以上5种现象会导致OS将线程优先级提高.

 

针对饥饿线程:

系统线程“平衡集管理器(balance set manager)” 每秒钟扫描一次就绪队列,发现是否存在等待时间超过300个时钟中断间隔的线程
    平衡集管理器将这些线程的优先级提升到15(最高),并分配给它一个长度为正常值4倍的时间配额
  当被提升的线程用完它的时间配额后,立即衰减到它原来的基本优先级(维护平衡)

 

 

 作者水平有限,文章肯定有错还请各位指点!!!感谢!!!

 

处理器调度