一、CPU调度概述
1.长程调度
- 又称作业调度或高级调度
- 处于新建状态的进程一般首先被放到外存的进程池中,当内存进程的数量没有达到最多进程数时,操作系统的调度程序才从新建状态选择一个进入内存并转换为就绪状态
- “新建”状态转换到“就绪”状态
- 由调度程序选择
- 控制多道程序的“道/度”
2.短程调度
- 又称为CPU调度或低级调度
- 在就绪队列中可能存在不止一个进程,当CPU空闲时,操作系统就需要从就绪队列中挑选一个进程让它运行
3.长程调度与短程调度的比较
4.中程调度
- 又称为交换
- 从本质上讲,中程调度不属于进程管理的内容,而应该属于内存管理
- 一个进程在内存和外存间的换进换出,最大的目的是节省内存
- 当一个进程在内存中长期不运行时,会造成内存浪费,为此,操作系统把这些进程从内存换道外存,从而腾出内存空间供运行进程使用
- 当一个在外存的进程接下来需要运行时,操作系统则执行还如操作,把这个进程从外存换入内存
5.进程调度队列
- 为了方便进行CPU调度,操作系统需要对不同状态的进程进行组织和管理。为此操作系统为某些特定的状态设立了一个或多个进程队列,用于管理这些进程
- 作业队列:在系统中的所有进程的集合
- 就绪队列:在主存中的,就绪并等待执行的所有进程的集合,不必是先进先出队列,队列中的记录通常是进程控制块(PCB)
- 设备队列:等待某一I/O设备的进程队列
- 进程的执行过程实际上就是进程在各种队列之间的迁移
6.CPU调度过程
- 调度程序
- 根据某种策略选择内存中的一个就绪进程
- 一个CPU同时只能运行一个进程
- 做选择
- 分派程序
- 负责把CPU的控制权转交CPU调度程序
- 切换上下文
- 切换到用户态
- 跳转到用户程序的适当位置并重新运行之
- 分派延迟:分派程序终止一个进程的运行并启动另一个进程运行所花的时间
7.调度方式
- 非抢占式调度
- 一旦把CPU分配给某个进程后,系统不可以抢占已分配的CPU并分配给其他进程
- 只有进程自愿释放CPU,才可以把CPU分配给其他进程
- 优点:容易实现,调度开销小,适合批处理系统
- 缺点:响应时间长,不合适交互系统
- 抢占式调度
- 调度程序可以根据某种原则暂停某个正在执行的进程,将已分配给它的CPU重新分配给另一个进程
- 当多个进程共享数据时,抢占调度可能导致竞争情况
- 抢占也影响操作系统的内核设计
- 可防止单一进程长时间独占CPU
- 系统开销大
- 受中断影响的代码应加以保护,从而避免同时使用,为了这些代码段不被多个进程同时访问,在进入时禁止中断而退出时启用中断
- 抢占式与非抢占式的区分
- 运行进程是否是自愿放弃CPU
- 运行进程是否是自愿放弃CPU
8.CPU调度时机
- CPU调度可能发生在当一个进程
- 从运行转到等待(非抢占式)
- 从运行转到就绪(抢占式)
- 从等待转到就绪(抢占式)
- 终止运行(非抢占式)
二、调度准则
- CPU利用率:固定时间内CPU运行时间的比例
- 吞吐量:单位时间内运行完的进程数
- 周转时间:进程从提交到运行结束的全部时间
- 等待时间:进程等待调度(不在运行)的时间片总和
- 响应时间:从进程提出请求到首次被响应(而不是输出结果)的时间段(在分时系统环境下),也就是第一段的等待时间
- 周转时间=等待时间+运行时间
- 带权周转时间:周转时间/运行时间
三、调度算法
1.先来先服务调度算法(FCFS)
- 调度策略:按照进程请求CPU的先后顺序来使用CPU
- 调度依据:进入就绪队列的时间
- 调度方法:先进入就绪队列的进程被优先选中运行
- 使用FIFO队列实现
- 特点:
- 实现简单,可使用FIFO队列实现
- 非抢占式调度
- 公平,每个进程都有被调度的机会
- 适用于长程调度,后台批处理系统的短程调度
- 对长CPU脉冲的进程有利,对短CPU脉冲的进程不利
- 护航效果:当一个长进程后面的多个短进程,让长进程先执行,会让后面的短进程等待较长时间,从而导致CPU和设备利用率降低
- 例:
2.短作业优先调度算法(SJF)
- 调度策略:关联到每个进程下次运行的CPU脉冲长度,调度最短的进程
- 调度依据:每个进程下次运行的CPU脉冲长度
- 调度方法:调度最短的进程运行
- 两种模式:
- 非抢占式调度:一旦进程拥有CPU,它可在该CPU脉冲结束后让出CPU
- 抢占式调度:有比当前进程剩余时间更短的进程到达时,新来的进程抢占当前运行进程的CPU,也称为最短剩余时间优先调度
- SJF最优:对一组的进程而言,它给出了最短的平均等待时间
- SJF算法困难:如何知道下一个CPU区间的长度
- SJF通常用于长程调度
- 指数估算法:通过先前的CPU区间长度及其指数平均进行预测
- 饥饿:长进程可能长时间等待,知道进程会运行但不知道什么时候运行
- 死锁:进程长时间等待,不会运行
- 例:
3.优先级调度算法
- 目前主流的操作系统调度算法
- 调度依据:优先级
- 就绪队列中的排列方式:优先级高的在前,优先级低的在后
- 调度方法:调度优先级最高进程运行
- 优先数:表示优先级的整数
- 可以参考不同的因素来设置(时间极限,内存要求,进程的重要性)
- 优先数可用某一范围的整数来表示
- 静态优先级:
- 进程创建时确定,在运行期间不变
- 简单易行,系统开销小
- 不够精确,可能会出现饥饿问题
- 动态优先级:
- 进程创建时的优先级随进程推进或等待时间增加而改变
- 调度模式:
- 抢占式调度
- 非抢占式调度
- 特点:
- 实现简单,考虑了进程的紧迫程度
- 策略灵活,可模拟其他算法
- 存在问题:饥饿(低优先级的进程可能永远得不到运行)
- 解决问题:视进程等待时间的延长提高其优先级
- 例:
4.时间片轮转(RR)
- 为分时系统设计
- 算法原理:把一段时间分割成若干个小碎片,每个需要运行的进程获得一个碎片运行,即在这段时间内,每个进程都得到运行
- 时间片:较小单位的CPU时间,通常为10-100毫秒
- RR算法的性能很大程度上取决于时间片的大小
- 时间片大->FCFS
- 时间片小->系统开销大
- 一般准则:时间片/10>进程上下文切换时间
- 周转时间也依赖时间片的大小
- 调度依据:进入就绪队列的时间
- 调度方法:每个进程运行时间长度为一个时间片,时间片用完后,该进程被抢占并插入就绪队列末尾
- 假定就绪队列中有n个进程、时间片q
- 则每个进程每次得到不超过q单位的成块CPU时间
- 没有一个进程的等待时间会超过(n-1)q
- 在不超过nq时间内,n个进程都运行一次
- 例:
5.多级队列调度(MLQ)
- 以上算法存在局限性,不能适应各种不同类型的进程
- SJF算法有利于短进程,而不利于长进程
- RR算法系统开销大
- 优先级算法存在饥饿问题等
- 所有进程采用同一策略,不合理
- 不同类型的进程需要不同策略
- 交互进程需要较短的响应时间
- 批处理进程需要较短的等待时间
- 通常,交互进程较批处理进程的优先级高
- 多级队列调度
- 允许系统中存在多个就绪队列,每个就绪队列有自己的调度算法
- 根据进程属性,如内存大小、进程优先级、进程类型等,一个进程永远分到一个队列,每个队列有自己的调度算法
- 队列之间应有调度
- 通常采用固定优先级抢占调度,可能产生饥饿
- 另一种方法是在队列之间划分时间片,每个队列都有一定比例的CPU时间,可用于调度队列内的进程
- 关键:
- 需要确定就绪队列的数量
- 需要确定新进程进入那个队列
- 需要确定每一个队列的调度算法
- 例:
- 就绪队列:
- 前台(交互式)
- 后台(批处理)
- 每个队列有自己的调度算法
- 前台:RR
- 后台:FCFS
- 队列间的调度方法
- 固定优先级调度,即前台运行完后再运行后台。有可能产生饥饿
- 给定时间片调度,即每个队列得到一定的CPU时间,进程在给定时间内执行;如,80%的时间执行前台的RR调度,20%的时间 执行后台的FCFS调度
- 就绪队列:
6.多级反馈队列调度(MLFQ)
- 多级反馈队列调度算法的核心是进程在运行过程中,能在不同队列间移动
- 进程能在不同的队列间移动:可实现老化
- 一种用于避免资源调度系统中的饥饿的技术
- 多级反馈队列调度程序由以下参数定义:
- 队列数
- 每一队列的调度算法
- 决定需要服务的进程将进入哪个队列的方法
- 决定进程升级的方法(低级队列到高级队列)
- 决定进程降级的方法(高级队列到低级队列)
- 优点:
- 比MLQ算法具有更好的灵活性
- MLFQ很好地解决了CPU调度问题
- Unix,Solaris,Windows的调度算法一定程度上都是MLFQ的变种
- 例:
四、线程调度
1.概念
- 在支持线程的操作系统上,内核级线程(而不是进程)才是操作系统所调度的
- 用户级线程是由线程库来管理的,而内核并不知道它们
- 用户级线程为了运行在CPU上,最终映射到相关的内核级线程,但是这种映射可能不是直接的,可能采用轻量级进程
2.竞争范围
- 进程竞争范围(PCS):对于实现多对一和多对多模型的系统线程库会调度用户级线程,以便在可用轻量级进程(LWP)上运行,因为竞争CPU是发生在同一进程的线程之间
- PCS采用优先级调度,即调度程序选择运行具有最高优先级的、可运行的线程。
- 用户级线程的优先级是由程序员设置的,并不是由线程库调整的
- 允许一个更高优先级的线程来抢占当前运行的线程
- 系统竞争范围(SCS):决定哪个内核级线程调度到一个处理器上,采用SCS调度来竞争CPU,发生在系统内的所有线程之间
五、多处理调度
- 适用多核处理器的CPU调度
- 多个CPU可用时,CPU调度将更为复杂
1.多处理调度的方法
- 非对称多处理器(ASMP):仅一个处理器能处理系统数据结构,减轻了对数据的共享需求。由这个主处理器负责调度,处理所有调度决定、I/O处理以及其他系统活动,其他处理器只执行用户代码
- 对称多处理器(SMP):每个处理器决定自己的调度方案,主流方案
- 所有进程可能处于一个共同的就绪队列中,或每个处理器都有它自己的私有就绪队列
- 不管如何,调度这样进行:每个处理器的调度程序都检查共同就绪队列,以便选择执行一个进程
- 调度方法:和单处理器相似
2.处理器亲和性
- 由于缓存的无效或重新填充的代价高,大多数SMP系统试图避免将进程从一个处理器移到另一个处理器,而是试图让一个进程运行在同一个处理器上
- 进程要在某个给定的CPU上尽量长时间地运行而不被迁移到其他处理器的倾向性
- 高速缓存中的内容
- 软亲和性:当一个操作系统试图保持进程运行在同一个处理器上时(但不会保证它会这么做),进程通常不会在处理器之间频繁迁移
- 硬亲和性:进程不会在处理器之间迁移,有的系统提供系统调用,从而允许某个进程运行在某个处理器子集上
- 系统的内存架构可以影响处理器的亲和性
3.负载平衡
- 将任务平均分配给SMP系统的各个处理器
- 针对私有就绪队列,而对公共队列系统,负载平衡通常没有必要,因为一旦处理器空闲,它立刻从公共队列中取走一个可执行进程
- 和处理器亲和性矛盾
- 保持一个进程运行在同一个处理器上的好处是进程可以利用它在该处理器缓存内的数据。无论是从一个处理器向另一个处理器推或拉进程,都会失去这个好处
- 方法:
- 推迁移:
- 对于推迁移,一个特定的任务周期性地检查每个处理器的负载,如果发现不平衡,那么通过将进程从超载处理器推到空闲或不太忙的处理器,从而平均分配负载
- 拉迁移:
- 当空闲处理器从一个忙的处理器上拉一个等待任务时,发生拉迁移
- 推迁移和拉迁移不必相互排斥,事实上,在负载平衡系统中它们常被并行实现
- 推迁移:
4.单队列调度方法
- 系统有一个就绪队列。当任意一个CPU空闲时,就从就绪队列中选择一个进程到该CPU上运行
- 优点:
- 容易从单核调度算法推广到多核/多处理器
- 实现简单,负载均衡
- 缺点:
- 不具有亲和性,一个进程可能在不同时候被调度到不同的CPU
- 多核同时访问一个队列,会有加锁问题,从而严重影响调度的性能
5.多队列调度方法
- 系统有多个就绪队列,一般每个CPU一个队列。每个就绪队列有自己的调度算法,并且每个就绪队列的调度相对独立
- 优点:
- 亲和性好
- 不需要加锁
- 缺点:
- 负载不均衡
- 策略:‘偷’进程