4.1 CPU调度的相关概念
CPU调度:按照一定的调度算法从就绪队列中选择一个进程,把CPU的使用权交给被选中的进程,其任务就是控制、协调进程对CPU的竞争。如果没有就绪进程,系统会安排一个系统空闲进程或idle进程。
CPU调度所面临的场景:系统中有N个进程,等待上CPU运行,而有M个CPU,M>=1.而CPU需要决策给哪一个进程分配哪 一个CPU。
CPU调度主要解决三个问题:
- 按什么原则选择下一个要执行的进程——调度算法;
- 何时进行选择——调度时机;
- 如何让被选中的进程上CPU运行——调度过程(进程的上下文切换)。
CPU调度的时机为内核对中断/异常/系统调用处理后返回到用户态时:
- 进程正常终止或由于某种错误而终止;
- 新进程创建或一个等待进程变成就绪;
- 当一个进程从运行态进入阻塞态;
- 当一个进程从运行态变为就绪态。
进程调度程序从就绪队列选择了要运行的进程:这个进程可以是刚刚被暂停执行的进程,也可能是另一个新的进程。如果是新的进程,则需进行进程切换。
进程切换:指一个进程让出处理器,另一个进程占用处理器的过程。主要包括以下两部分:
- 切换全局页目录以加载一个新的地址空间;
- 切换内核栈和硬件上下文,其中硬件上下文包括了内核执行新进程所需要的全部信息,如CPU相关寄存器。
切换过程包括了对原来运行进程各种状态的保存以及对新进程的各种状态的恢复。
例如:如果进程A下CPU,B上CPU,则上下文切换具体步骤为:
- 保存进程A的上下文环境(程序计数器、程序状态字、其他寄存器);
- 用新状态和其他相关信息更新进程A的PCB;
- 把进程A移至合适的队列(就绪、阻塞);
- 将进程B的状态设置为运行态;
- 从进程B的PCB中恢复上下文(程序计数器、程序状态字、其他寄存器)。
上下文切换开销:
- 直接开销:内核完成切换所用的CPU时间(保存和恢复寄存器、切换地址空间(相关指令比较昂贵))
- 间接开销:高速缓存(Cache)、缓冲区缓存(Buffer Cache)和TLB(Translation Lookup Buffer)失效
CPU调度算法的设计:
- 从用户角度来说:
- 性能:周转时间短一点,响应时间快一点,紧急任务可以在最后期限完成;
- 其他:对自己的程序什么时候运行具有可预测性。
- 从系统角度
- 性能:吞吐量大一点,CPU利用率高一点;
- 公平性,强制优先级,平衡资源。
调度算法衡量指标:
- 吞吐量(Throughput):每单位时间完成的进程数目;
- 周转时间TT(Turnaround Time):每个进程从提出请求到运行完成时间;
- 响应时间RT(Response Time):从提出请求到第一次回应的时间;
- CPU利用率(CPU Utilization):CPU有效工作的时间比例;
- 等待时间(Waiting time):每一个进程在就绪队列(ready queue)中等待的时间。
4.2设计调度算法前的要点讨论
设计调度算法时要考虑:
- 进程控制块PCB中需要记录哪些与CPU调度有关的信息
- 进程优先级及就绪队列的组织
- 抢占式调度与非抢占式调度
- I/O密集型与CPU密集型进程
- 时间片进程的优先级(数)
优先级:表现出进程的重要性和紧迫性;
- 优先数:是一个数值,反映了某一个优先级。
- UNIX中,优先数小的,优先级高。
- 静态优先级:进程创建时指定,运行过程中不再改变;
- 动态优先级:进程创建时指定了一个优先级,运行过程中可以动态变化。
抢占与非抢占——指占用CPU的方式
- 可抢占式(可剥夺式):当有比正在运行的进程优先级更高的进程就绪时,系统可强行剥夺正在进行进程的CPU,提供给具有更高优先级的进程使用。
- 不可抢占式(不可剥夺式):某一进程被调度运行后,除非由于它自身的原因不能运行,否则一直运行下去。
I/O密集型与CPU密集型进程,按进程执行过程中的行为划分:
- I/O密集型或I/O型:频繁的进行I/O,通常会花费很多时间等待I/O操作的完成
- CPU密集型或CPU型或计算密集型(CPU-bound):需要大量的CPU时间进行计算。
时间片——一个时间段,分配给调度上CPU的进程,确定了允许该进程运行的时间长度。选择时间片应考虑:
- 进程切换的开销;
- 对响应时间的要求;
- 就绪进程个数;
- CPU能力;
- 进程的行为。
4.3批处理系统中常用的调度算法——考虑吞吐量、周转时间、CPU利用率、公平平衡
- 先来先服务(FCFS-First Come First Serve)——先进先出:按照进程就绪的先后顺序使用CPU,非抢占,优点:公平,实现简单;缺点:长进程后面的端进程需要等待很长时间,使用户体验较差;
- 最短作业优先(SJF-Shoutest Job First)——具有最短完成时间的进程优先执行,非抢占式,优点:最短的平均周转时间,即在所有进程同时可运行时,采用SJF调度算法可以得到最短的平均周转时间:缺点:不公平,源源不断的短任务到来,可能使长的任务长时间得不到运行,产生饥饿现象。
- 最短剩余时间优先(SRTN-Shortest Remaining Time Next)——SJF抢占式版本,即当一个新就绪的进程比当前运行进程具有更短的完成时间时,系统抢占当前进程,选择新就绪的进程执行。
- 最高响应比优先(HRRN-Highest Response Ratio Next)——是一个综合的算法,调度时,首先计算每个进程的响应比R;之后,总是选择R最高的进程执行。响应比R=周转时间/处理时间=(处理时间+等待时间)/处理时间=1+(等待时间/处理时间)。
4.4交互式系统的调度算法——考虑响应时间,公平平衡
- 时间片轮转调度(RR-Round Robin)——队列中的进程轮流上CPU,每次一个时间片。目标是为短任务改善平均响应时间,解决问题的思路在于通过周期性切换,每个进程分配一个时间片,通过时钟中断然后引发轮换达到目标。
如何选择合适的时间片
- 如果时间太长,则会降级为先来先服务算法,延长短进程的响应时间;
- 如果时间太短,即小于典型的交互时间,进程切换浪费CPU时间。
时间片轮转调度算法
- 优点:公平,有利于交互式计算,响应时间快,对不同大小的进程是有利的;
- 缺点:由于进程切换,时间片轮转算法要花费较高的开销。
- 最高优先级调度(HPF-Highest Priority First)——选择优先级最高的进程投入运行
- 通常:系统进程优先级高于用户进程,前台进程优先级高于后台进程,操作系统更偏好I/O型进程;
- 优先级可以是静态不变的,也可以动态调整,优先数可以决定优先级;
- 就绪队列可以按照优先级组织;
- 实现简单:不公平,容易产生饥饿现象;
- 基于优先级的抢占式调度算法,容易产生优先级反转问题,又称优先级反置、翻转、倒挂,其现象为:一个低优先级进程持有一个高优先级进程所需要的资源,使的高优先级进程等待低优先级进程运行。优先级反转问题,是一个系统错误,会使高优先级进程停滞不前,导致系统性能降低,可以通过设置优先级上限、优先级继承、使用中断禁止三种方式来解决此问题。
- 多级反馈队列(Multiple feedback queue)——是unix的一个分支BSD5.3版所采用的调度算法,是一个综合调度算法,考虑各种因素后进行折中权衡的算法。
- 设置多个就绪队列,第一级队列优先级最高;
- 给不同就绪队列中的进程分配长度不同的时间片,第一级队列中的时间片最小,随着队列优先级别的降低,时间片增大;
- 当第一级队列为空时,在第二级队列调度,以此类推;
- 各级队列按照时间片轮转方式进行调度;
- 当一个新创建进程就绪后,进入第一级队列;
- 进程用完时间片而放弃CPU,进入下一级就绪队列;
- 由于阻塞而放弃CPU的进程进入相应的等待队列,一旦等待的事件发生,该进程回到原来一级就绪队列;
- 若允许抢占,则当有一个优先级更高的进程就绪时,可以抢占CPU,被抢占的进程回到原来一级就绪队列末尾。
- 最短进程优先(Shortest Process Next)
多处理器调度算法需要考虑的问题:
- 不仅要决定选择哪一个进程执行,还要决定在哪一个CPU上执行;
- 要考虑进程在多个CPU之间迁徙时的开销,包括:
- 高速缓存失效、TLB失效的开销;
- 尽可能使进程总是在同一个CPU上执行;
- 考虑负载均衡问题。
4.5典型系统所采用的调度算法
Unix采用动态优先数法,5.3BSD采用多级反馈队列法,linux采用抢占式调度算法,Windows采用基于优先级的抢占式多任务调度算法,Solaris采用综合调度算法 。
- Windows线程调度:调度单位是线程,采用基于动态优先级的抢占式调度,结合时间配额的调整:
- 就绪线程按优先级进入相应队列;
- 系统总是选择优先级最高的就绪线程运行;
- 同一优先级的各种线程按时间片轮转进行调度;
- 多CPU系统中允许多个线程并行运行。
Windows系统引发线程调度的条件:
- 一个线程的优先级改变了;
- 有个线程改变了它的亲和处理机集合;
- 线程正常终止或由于某种错误而终止;
- 新线程创建或一个等待线程变成就绪;
- 当一个线程从运行态进入阻塞态;
- 当一个线程从运行态变为就绪态。
Windows使用32个线程优先级,分成三类:
- 实时优先级(16-31):实时优先级线程不改变其优先级;
- 可变优先级(1-15):其优先级可以在一定范围内升高或降低,可以区分基本优先级和当前优先级;
- 系统线程(0):零页线程:用于对系统中空闲物理页面清零。
时间配额:不是一个时间长度值,而是一个称为配额单位的整数。一个线程用完了自己的时间配额时,如果没有其他相同优 级的线程,Windows将重新给该线程分配一个新的时间配额,让它继续运行。
Windows线程调度策略:
- 主动切换;
- 抢占。当线程被抢占时,它被放回相应优先级的就绪队列的队首,处于实时优先级的线程在被抢占时,时间配额被重置为一个完整的时间配额,处于可变优先级的线程在被抢占时,时间配额不变,重新得到CPU后将运行剩下的时间配额。
- 时间配额用完。假设线程A的时间配额用完:a.A的优先级没有降低,如果队列中有其他就绪线程,选择下一个线程执行,A回到原来的就绪队列末尾,如果队列中没有其他就绪线程,系统给线程A分配一个新的时间配额,让它继续运行;b.A的优先级降低了,Windows将选择一个更高优先级的线程执行。
Windows会针对下列五种情况,提升线程的当前优先级:
- I/O操作完成;
- 信号量或时间等待结束;
- 前台进程中的线程完成一个等待操作;
- 由于窗口活动而唤醒窗口线程;
- 线程处于就绪态超过了一定的时间还没有运行——饥饿现象。