CPU 调度

408答疑


文章目录


CPU 调度

2.2.1 调度的概念

1. 调度的基本概念

  • 在多道程序系统中,进程的数量往往多于 CPU 的个数,因此进程争用 CPU 的情况在所难免。
  • CPU 调度是对 CPU 进行分配,即从就绪队列中按照一定的算法(公平、高效的原则)选择一个进程并将 CPU 分配给它运行,以实现进程并发地执行。
  • CPU 调度是多道程序操作系统的基础,是操作系统设计的核心问题。

2. 调度的层次

  • 一个作业从提交开始直至完成,往往要经历以下三级调度,如下图所示。
(1)高级调度(作业调度)
  • 按照某种规则从外存上处于后备队列的作业中挑选一个(或多个),给它(们)分配内存、I/O 设备等必要的资源,并建立相应的进程,以使它(们)获得竞争 CPU 的权利。
  • 简言之,作业调度就是内存与辅存之间的调度。
  • 每个作业只调入一次、调出一次。
  • 多道批处理系统中大多配有作业调度,而其他系统中通常不需要配置作业调度。
(2)中级调度(内存调度)
  • 引入中级调度的目的是提高内存利用率和系统吞吐量。
  • 为此,将那些暂时不能运行的进程调至外存等待,此时进程的状态称为挂起态。
  • 当它们已具备运行条件且内存又稍有空闲时,由中级调度来决定将外存上的那些已具备运行条件的挂起进程再重新调入内存,并修改其状态为就绪态,挂在就绪队列上等待。
  • 中级调度实际上是存储器管理中的对换功能。
(3)低级调度(进程调度)
  • 按照某种算法从就绪队列中选取一个进程,将 CPU 分配给它。
  • 进程调度是最基本的一种调度,在各种操作系统中都必须配置这级调度。
  • 进程调度的频率很高,一般几十毫秒一次。

3. 三级调度的联系

  • 作业调度从外存的后备队列中选择一批作业进入内存,为它们建立进程,这些进程被送入就绪队列,进程调度从就绪队列中选出一个进程,并将其状态改为运行态,将 CPU 分配给它。
  • 中级调度是为了提高内存的利用率,系统将那些暂时不能运行的进程挂起来。
    • 1)作业调度为进程活动做准备,进程调度使进程正常活动起来。
    • 2)中级调度将暂时不能运行的进程挂起,中级调度处于作业调度和进程调度之间。
    • 3)作业调度次数少,中级调度次数略多,进程调度频率最高。
    • 4)进程调度是最基本的,不可或缺。

2.2.2 调度的实现

1. 调度程序(调度器)

  • 用于调度和分派 CPU 的组件称为调度程序,它通常由三部分组成,如下图所示。
    • 1)排队器。

      • 将系统中的所有就绪进程按照一定的策略排成一个或多个队列,以便于调度程序选择。
      • 每当有一个进程转变为就绪态时,排队器便将它插入相应的就绪队列。
    • 2)分派器。

      • 依据调度程序所选的进程,将其从就绪队列中取出,将 CPU 分配给新进程。
    • 3)上下文切换器。

      • 在对 CPU 进行切换时,会发生两对上下文的切换操作:
        • 第一对,将当前进程的上下文保存到其 PCB 中,再装入分派程序的上下文,以便分派程序运行;
        • 第二对,移出分派程序的上下文,将新选进程的 CPU 现场信息装入 CPU 的各个相应寄存器。

在上下文切换时,需要执行大量 load 和 store 指令,以保存寄存器的内容,因此会花费较多时间。现在已有硬件实现的方法来减少上下文切换时间。通常采用两组寄存器,其中一组供内核使用,一组供用户使用。这样,上下文切换时,只需改变指针,让其指向当前寄存器组即可。

2. 调度的时机、切换与过程

  • 调度程序是操作系统内核程序。

  • 请求调度的事件发生后,才可能运行调度程序,调度了新的就绪进程后,才会进行进程切换。

  • 理论上这三件事应该顺序执行,但在实际的操作系统内核程序运行中,若某时刻发生了引起进程调度的因素,则不一定能马上进行调度与切换。

  • 现代操作系统中,应该进行进程调度与切换的情况如下:

    • 1)创建新进程后,父进程和子进程都处于就绪态,因此需要决定是运行父进程还是运行子进程,调度程序可以合法地决定其中一个进程先运行。
    • 2)进程正常结束或异常终止后,必须从就绪队列中选择某个进程运行。若没有就绪进程,则通常运行一个系统提供的闲逛进程。
    • 3)当进程因 I/O 请求、信号量操作或其他原因被阻塞时,必须调度其他进程运行。
    • 4)当 I/O 设备准备就绪,发出 I/O 中断,原先等待 I/O 的进程从阻塞态变为就绪态,此时需要决定是让新的就绪进程投入运行,还是让中断发生时运行的进程继续执行。
  • 此外,在有些系统中,当有更紧急的任务(如更高优先级的进程进入就绪队列)需要处理时,或者当前进程的时间片用完时,也会被强行剥夺 CPU。

  • 进程切换往往在调度完成后立刻发生,它要求保存原进程当前断点的现场信息,恢复被调度进程的现场信息。

  • 现场切换时,操作系统内核将原进程的现场信息推入当前进程的内核堆栈来保存它们,并更新堆栈指针。

  • 内核完成从新进程的内核栈中装入新进程的现场信息、更新当前运行进程空间指针、重设 PC 寄存器等相关工作之后,开始运行新的进程。

  • 不能进行进程的调度与切换的情况如下:

    • 1)在处理中断的过程中。中断处理过程复杂,在实现上很难做到进程切换,而且中断处理是系统工作的一部分,逻辑上不属于某一进程,不应被剥夺 CPU 资源。
    • 2)需要完全屏蔽中断的原子操作过程中。如加锁、解锁、中断现场保护、恢复等原子操作。
  • 在原子过程中,连中断都要屏蔽,更不应该进行进程调度与切换。

  • 若在上述过程中发生了引起调度的条件,则不能马上进行调度和切换,应置系统的请求调度标志,直到上述过程结束后才进行相应的调度与切换。

3. 进程调度的方式

  • 所谓进程调度方式,是指当某个进程正在 CPU 上执行时,若有某个更为重要或紧迫的进程需要处理,即有优先权更高的进程进入就绪队列,此时应如何分配 CPU。
  • 通常有以下两种进程调度方式:
1)非抢占调度方式
  • 也称非剥夺方式。
  • 是指当一个进程正在 CPU 上执行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在执行的进程继续执行,直至该进程运行完成(如正常结束、异常终止)或发生某种事件(如等待 I/O 操作、在进程通信同步中执行了 Block 原语)而进入阻塞态时,才将 CPU 分配给其他进程。
  • 非抢占调度方式的优点是实现简单、系统开销小,适用于早期的批处理系统,但它不能用于分时系统和大多数的实时系统。
2)抢占调度方式
  • 也称剥夺方式。
  • 是指当一个进程正在 CPU 上执行时,若有某个更为重要或紧迫的进程需要使用 CPU,则允许调度程序根据某种原则去暂停正在执行的进程,将 CPU 分配给这个更为重要或紧迫的进程。
  • 抢占调度方式对提高系统吞吐率和响应效率都有明显的好处。
  • 但"抢占"不是一种任意性行为,必须遵循一定的原则,主要有优先权、短进程优先和时间片原则等。

4. 闲逛进程

  • 当进程切换时,若系统中没有就绪进程,则会调度闲逛进程(Idle Process)运行,它的 PID 为 0。
  • 若没有其他进程就绪,则该进程就一直运行,并在指令周期后测试中断。
  • 闲逛进程的优先级最低,没有就绪进程时才会运行闲逛进程,只要有进程就绪,就会立即让出 CPU。
  • 闲逛进程不需要 CPU 之外的资源,它不会被阻塞。

5. 两种线程的调度

1)用户级线程调度
  • 因为内核并不知道线程的存在,所以内核还是和以前一样,选择一个进程,并给予时间控制。
  • 由进程中的调度程序决定哪个线程运行。
2)内核级线程调度
  • 内核选择一个特定线程运行,通常不用考虑该线程属于哪个进程。

  • 对被选择的线程赋予一个时间片,若超过了时间片,则会强制挂起该线程。

  • 用户级线程的线程切换在同一进程中进行,仅需少量的机器指令;

  • 内核级线程的线程切换需要完整的上下文切换、修改内存映像、使高速缓存失效,这就导致了若干数量级的延迟。

2.2.3 调度的目标

  • 不同的调度算法具有不同的特性,在选择调度算法时,必须考虑算法的特性。

  • 为了比较 CPU 调度算法的性能,人们提出了很多评价标准,下面介绍其中主要的几种:

    • 1)CPU 利用率。
      • CPU 是计算机系统中最重要和昂贵的资源之一,所以应尽可能使 CPU 保持"忙"状态,使这一资源利用率最高。
      • CPU 利用率的计算方法如下:
        C P U 的利用率 = C P U 有效工作时间 C P U 有效工作时间 + C P U 空闲等待时间 CPU的利用率=\frac{CPU有效工作时间}{CPU有效工作时间+CPU空闲等待时间} CPU的利用率=CPU有效工作时间+CPU空闲等待时间CPU有效工作时间

    注意

    计算作业完成时间时,要注意 CPU 与设备、设备与设备之间是可以并行的。

    • 2)系统吞吐量。

      • 表示单位时间内 CPU 完成作业的数量。
      • 长作业需要消耗较长的 CPU 时间,因此会降低系统的吞吐量。
      • 而对于短作业,需要消耗的 CPU 时间较短,因此能提高系统的吞吐量。
      • 调度算法和方式的不同,也会对系统的吞吐量产生较大的影响。
    • 3)周转时间。

      • 指从作业提交到作业完成所经历的时间,是作业等待、在就绪队列中排队、在 CPU 上运行及 I/O 操作所花费时间的总和。
      • 周转时间的计算方法如下:
        周转时间 = 作业完成时间 − 作业提交时间 周转时间=作业完成时间-作业提交时间 周转时间=作业完成时间−作业提交时间
      • 平均周转时间是指多个作业周转时间的平均值:
        平均周转时间 = ( 作业 1 的周转时间 + ⋯ + 作业 n 的周转时间 ) / n 平均周转时间=(作业1的周转时间+\cdots+作业n的周转时间)/n 平均周转时间=(作业1的周转时间+⋯+作业n的周转时间)/n
      • 带权周转时间是指作业周转时间与作业实际运行时间的比值:
        带权周转时间 = 作业周转时间 作业实际运行时间 带权周转时间=\frac{作业周转时间}{作业实际运行时间} 带权周转时间=作业实际运行时间作业周转时间
      • 平均带权周转时间是指多个作业带权周转时间的平均值:
        平均带权周转时间 = ( 作业 1 的带权周转时间 + ⋯ + 作业 n 的带权周转时间 ) / n 平均带权周转时间=(作业1的带权周转时间+\cdots+作业n的带权周转时间)/n 平均带权周转时间=(作业1的带权周转时间+⋯+作业n的带权周转时间)/n
    • 4)等待时间。

      • 指进程处于等待 CPU 的时间之和,等待时间越长,用户满意度越低。
      • CPU 调度算法实际上并不影响作业执行或 I/O 操作的时间,只影响作业在就绪队列中等待所花的时间。
      • 因此,衡量一个调度算法的优劣,常常只需简单地考察等待时间。
    • 5)响应时间。

      • 指从用户提交请求到系统首次产生响应所用的时间。
      • 在交互式系统中,周转时间不是最好的评价准则,一般采用响应时间作为衡量调度算法的重要准则之一。
      • 从用户角度来看,调度策略应尽量降低响应时间,使响应时间处在用户能接受的范围之内。
  • 要想得到一个满足所有用户和系统要求的算法几乎是不可能的。

  • 设计调度程序,一方面要满足特定系统用户的要求(如某些实时和交互进程的快速响应要求),另一方面要考虑系统整体效率(如减少整个系统的进程平均周转时间),同时还要考虑调度算法的开销。

2.2.4 进程切换

  • 对通常的进程而言,其创建、撤销及要求由系统设备完成的 I/O 操作,都是利用系统调用而进入内核,再由内核中的相应处理程序予以完成的。
  • 进程切换同样是在内核的支持下实现的,因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。

(1)上下文切换

  • 切换 CPU 到另一个进程需要保存当前进程状态并恢复另一个进程的状态,这个任务称为上下文切换。
  • 进程上下文采用进程 PCB 表示,包括 CPU 寄存器的值、进程状态和内存管理信息等。
  • 当进行上下文切换时,内核将旧进程状态保存在其 PCB 中,然后加载经调度需要执行的新进程的上下文。
  • 在切换过程中,进程的运行环境产生实质性的变化。
  • 上下文切换的流程如下:
    • 1)挂起一个进程,将 CPU 上下文保存到 PCB,包括程序计数器和其他寄存器。
    • 2)将进程的 PCB 移入相应的队列,如就绪、在某事件阻塞等队列。
    • 3)选择另一个进程执行,并更新其 PCB。
    • 4)恢复新进程的 CPU 上下文。
    • 5)跳转到新进程 PCB 中的程序计数器所指向的位置执行。

(2)上下文切换的消耗

  • 上下文切换通常是计算密集型的,即它需要相当可观的 CPU 时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间,所以上下文切换对系统来说意味着消耗大量的 CPU 时间。
  • 有些 CPU 提供多个寄存器组,这样,上下文切换就只需要简单改变当前寄存器组的指针。

(3)上下文切换与模式切换

  • 模式切换与上下文切换是不同的,模式切换时,CPU 逻辑上可能还在执行同一进程。
  • 用户进程最开始都运行在用户态,若进程因中断或异常进入内核态运行,执行完后又回到用户态刚被中断的进程运行。
  • 用户态和内核态之间的切换称为模式切换,而不是上下文切换,因为没有改变当前的进程。
  • 上下文切换只能发生在内核态,它是多任务操作系统中的一个必需的特性。

注意

调度和切换的区别:调度是指决定资源分配给哪个进程的行为,是一种决策行为;切换是指实际分配的行为,是执行行为。一般来说,先有资源的调度,然后才有进程的切换

2.2.5 CPU 调度算法

  • 操作系统中存在多种调度算法,有的调度算法适用于作业调度,有的调度算法适用于进程调度,有的调度算法两者都适用。
  • 下面介绍几种常用的调度算法。

1. 先来先服务(FCFS)调度算法

  • FCFS 调度算法是一种最简单的调度算法,它既可用于作业调度,又可用于进程调度。

  • 在作业调度中,FCFS 调度算法每次从后备作业队列中选择最先进入该队列的一个或几个作业,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。

  • 在进程调度中,FCFS 调度算法依次从就绪队列中选择最先进入该队列的进程,将 CPU 分配给它,使之投入运行,直到运行完成或因某种原因阻塞时才释放 CPU。

  • 下面通过一个实例来说明 FCFS 调度算法的性能。

  • 假设系统中有 4 个作业,它们的提交时间分别是 8、8.4、8.8、9,运行时间依次是 2、1、0.5、0.2,系统采用 FCFS 调度算法,这组作业的平均等待时间、平均周转时间和平均带权周转时间可见下表。

作业号 提交时间 运行时间 开始时间 等待时间 完成时间 周转时间 带权周转时间
1 8 2 8 0 10 2 1
2 8.4 1 10 1.6 11 2.6 2.6
3 8.8 0.5 11 2.2 11.5 2.7 5.4
4 9 0.2 11.5 2.5 11.7 2.7 13.5
[FCFS 调度算法的性能]

平均等待时间 t = ( 0 + 1.6 + 2.2 + 2.5 ) / 4 = 1.575 t=(0+1.6+2.2+2.5)/4=1.575 t=(0+1.6+2.2+2.5)/4=1.575

平均周转时间 T = ( 2 + 2.6 + 2.7 + 2.7 ) / 4 = 2.5 T=(2+2.6+2.7+2.7)/4=2.5 T=(2+2.6+2.7+2.7)/4=2.5

平均带权周转时间 W = ( 1 + 2.6 + 5.4 + 13.5 ) / 4 = 5.625 W=(1+2.6+5.4+13.5)/4=5.625 W=(1+2.6+5.4+13.5)/4=5.625

  • FCFS 调度算法属于不可剥夺算法。
  • 从表面上看,它对所有作业都是公平的,但若一个长作业先到达系统,就会使后面的许多短作业等待很长时间,因此它不能作为分时系统和实时系统的主要调度策略。
  • 但它常被结合在其他调度策略中使用。例如,在使用优先级作为调度策略的系统中,往往对多个具有相同优先级的进程按 FCFS 原则处理。
  • FCFS 调度算法的特点是算法简单,效率较低;对长作业比较有利,但对短作业不利(相对 SJF 和高响应比而言);有利于 CPU 繁忙型作业,而不利于 I/O 繁忙型作业。

2. 短作业优先(SJF)调度算法

  • 短作业(进程)优先调度算法是指对短作业(进程)优先调度的算法。

  • 短作业优先(SJF)调度算法从后备队列中选择一个或几个估计运行时间最短的作业,将它们调入内存中运行;短进程优先(SPF)调度算法从就绪队列中选择一个估计运行时间最短的进程,将 CPU 分配给它,使之立即执行,直到完成或发生某些事件而阻塞时再释放 CPU。

  • 例如,考虑下表中给出的一组作业,若系统采用短作业优先调度算法,其平均等待时间、平均周转时间和平均带权周转时间可见下表。

作业号 提交时间 运行时间 开始时间 等待时间 完成时间 周转时间 带权周转时间
1 8 2 8 0 10 2 1
2 8.4 1 10.7 2.3 11.7 3.3 3.3
3 8.8 0.5 10.2 1.4 10.7 1.9 3.8
4 9 0.2 10 1 10.2 1.2 6
[SJF 调度算法的性能]

平均等待时间 t = ( 0 + 2.3 + 1.4 + 1 ) / 4 = 1.175 t=(0+2.3+1.4+1)/4=1.175 t=(0+2.3+1.4+1)/4=1.175

平均周转时间 T = ( 2 + 3.3 + 1.9 + 1.2 ) / 4 = 2.1 T=(2+3.3+1.9+1.2)/4=2.1 T=(2+3.3+1.9+1.2)/4=2.1

平均带权周转时间 W = ( 1 + 3.3 + 3.8 + 6 ) / 4 = 3.525 W=(1+3.3+3.8+6)/4=3.525 W=(1+3.3+3.8+6)/4=3.525

  • SJF 算法也存在不容忽视的缺点:

    • 1)该算法对长作业不利。由上面两张表可知,SJF 调度算法中长作业的周转时间会增加。更严重的是,若有一长作业进入系统的后备队列,由于调度程序总是先调度那些(估计)运行时间短的作业,将导致长作业长期不被调度,产生饥饿现象。
    • 2)该算法完全未考虑作业的紧迫程度,因此不能保证紧迫性作业会被及时处理。
    • 3)由于作业的长短是根据用户所提供的估计执行时间而定的,而用户又可能有意无意地缩短其作业的估计运行时间,致使该算法不一定能真正做到短作业优先调度。
  • SPF 算法也可以是抢占式的(若未特别说明,原则认为非抢占式)。

  • 当一个新进程到达就绪队列时,若其估计执行时间比当前进程的剩余时间小,则立即暂停当前进程,将 CPU 分配给新进程。

  • 因此,抢占式 SPF 调度算法也称最短剩余时间优先调度算法。

注意

短作业(SJF)调度算法的平均等待时间、平均周转时间是最优的。

3. 高响应比优先调度算法

  • 高响应比优先调度算法主要用于作业调度,是对 FCFS 调度算法和 SJF 调度算法的一种综合平衡,同时考虑了每个作业的等待时间和估计的运行时间。

  • 在每次进行作业调度时,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行。

  • 响应比的变化规律可描述为:
    响应比 R p = 等待时间 + 要求服务时间 要求服务时间 响应比R_p=\frac{等待时间+要求服务时间}{要求服务时间} 响应比Rp=要求服务时间等待时间+要求服务时间

  • 根据公式可知:

    • ①作业的等待时间相同时,要求服务时间越短,响应比越高,有利于短作业,因此类似于 SJF。
    • ②要求服务时间相同时,作业的响应比由其等待时间决定,等待时间越长,其响应比越高,因此类似于 FCFS。
    • ③对于长作业,作业的响应比可以随等待时间的增加而提高,当其等待时间足够长时,也可获得 CPU,克服了"饥饿"现象。

4. 优先级调度算法

  • 优先级调度算法既可用于作业调度,又可用于进程调度。

  • 该算法中的优先数用于描述作业的紧迫程度。

  • 在作业调度中,优先级调度算法每次从后备作业队列中选择优先级最高的一个或几个作业,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。

  • 在进程调度中,优先级调度算法依次从就绪队列中选择优先级最高的进程,将 CPU 分配给它,使之投入运行。

  • 根据新的更高优先级进程能否抢占正在执行的进程,可将优先级调度算法分为以下两种:

    • 1)非抢占式优先级调度算法。当一个进程正在 CPU 上运行时,即使有某个优先级更高的进程进入就绪队列,仍让正在运行的进程继续运行,直到由于其自身的原因让出 CPU 时(任务完成或等待事件),才将 CPU 分配给就绪队列中优先级最高的进程。

    • 2)抢占式优先级调度算法。当一个进程正在 CPU 上运行时,若有某个优先级更高的进程进入就绪队列,则立即暂停正在运行的进程,将 CPU 分配给优先级最高的进程。

  • 而根据进程创建后其优先级是否可以改变,可将进程优先级分为以下两种:

    • 1)静态优先级。
      • 优先级是在创建进程时确定的,且在进程的整个运行期间保持不变。
      • 确定静态优先级的主要依据有进程类型、进程对资源的要求、用户要求。
      • 优点是简单易行,系统开销小,缺点是很难准确地确定优先级提升规律。
    • 2)动态优先级。
      • 创建进程时先赋予进程一个优先级,但优先级会随进程的推进或等待时间的增加而改变,以便获得更好的调度性能。
      • 例如,规定优先级随等待时间的增加而提高,于是,对于优先级初值较低的进程,在等待了足够长的时间后也可获得 CPU。
  • 一般来说,进程优先级的设置可以参照以下原则:

    • 1)系统进程 > 用户进程。系统进程作为系统的管理者,理应拥有更高的优先级。
    • 2)交互型进程 > 非交互型进程(或前台进程 > 后台进程)。大家平时在使用手机时,在前台运行的正在和你交互的进程应该更快地响应你,因此自然需要被优先处理。
    • 3)I/O 型进程 > 计算型进程。
      • 所谓 I/O 型进程,是指那些会频繁使用 I/O 设备的进程,而计算型进程是那些频繁使用 CPU 的进程(很少使用 I/O 设备)。
      • 我们知道,I/O 设备(如打印机)的处理速度要比 CPU 慢得多,因此将 I/O 型进程的优先级设置得更高,就更有利于 I/O 设备尽早开始工作,从而提升系统的整体效率。

5. 时间片轮转(RR)调度算法

  • 时间片轮转(RR)调度算法主要适用于分时系统。

  • 这种算法最大的特点是公平,系统将所有的就绪进程按 FCFS 策略排成一个就绪队列,每隔一定的时间(如 30ms)便产生一次时钟中断,激活调度程序并进行调度,将 CPU 分配给就绪队列的队首进程,并令其执行一个时间片。

  • 若执行完一个时间片后,进程还未运行完成,它也必须释放 CPU(被剥夺),CPU 再分给就绪队列的新队首进程,而被剥夺的进程返回就绪队列的末尾重新排队,等候再次运行。

  • 在 RR 调度算法中,若一个时间片尚未用完而当前进程已运行完成,则调度程序会被立即激活;若一个时间片用完,则产生一个时钟中断,由时钟中断处理程序来激活调度程序。

  • 在 RR 调度算法中,时间片的大小对系统性能的影响很大。若时间片足够大,以至于所有进程都能在一个时间片内执行完毕,则时间片轮转调度算法就退化为先来先服务调度算法。若时间片很小,CPU 将在进程间过于频繁地切换,使 CPU 的开销增大,而真正用于运行用户进程的时间减少。

  • 因此,时间片的大小应选择适当,时间片的长短通常由以下因素确定:系统的响应时间、就绪队列中的进程数目和系统的处理能力。

6. 多级队列调度算法

  • 前述的各种调度算法,由于系统中仅设置一个进程的就绪队列,调度算法总是固定单一的,无法满足系统中不同用户对进程调度策略的不同要求。
  • 在多 CPU 系统中,这种单一调度策略实现机制的缺点更为突出,多级队列调度算法能在一定程度上弥补这一缺点。
  • 该算法在系统中设置多个就绪队列,将不同类型或性质的进程固定分配到不同的就绪队列。
  • 每个队列可设置不同的调度算法,因此,系统针对同一用户进程的需求,很容易提供多种调度策略。
  • 同一队列中的进程可以设置不同的优先级,不同的队列本身也可以设置不同的优先级。
  • 在多 CPU 系统中,可以很方便为每个 CPU 设置一个单独的就绪队列,每个 CPU 可实施各自不同的调度策略。

7. 多级反馈队列调度算法(综合了前几种算法的优点)

  • 多级反馈队列调度算法是时间片轮转调度算法和优先级调度算法的综合与发展,如下图所示。

  • 通过动态调整进程优先级和时间片大小,多级反馈队列调度算法可以兼顾多方面的系统目标。

  • 例如,为提高系统吞吐量和缩短平均周转时间而照顾短进程;为获得较好的 I/O 设备利用率和缩短响应时间而照顾 I/O 型进程;同时,也不必事先估计进程的执行时间。

  • 多级反馈队列调度算法的实现思想如下:

    • 1)设置多个就绪队列,并为每个队列赋予不同的优先级。第 1 级队列的优先级最高,第 2 级队列的优先级次之,其余队列的优先级逐个降低。
    • 2)赋予各个队列中的进程运行时间片的大小各不相同。在优先级越高的队列中,每个进程的时间片就越小。例如,第 i + 1 i+1 i+1 级队列的时间片要比第 i i i 级队列的时间片长 1 倍。
    • 3)每个队列都采用 FCFS 算法。新进程进入内存后,首先放入第 1 级队列的末尾,按 FCFS 原则排队。若能在该时间片内完成,便可撤离系统。若它在一个时间片结束时尚未完成,调度程序将其转入第 2 级队列的末尾等待调度;若它在第 2 级队列中运行一个时间片后仍未完成,再将它放入第 3 级队列,以此类推。当进程最后被降到第 n n n 级队列后,在第 n n n 级队列中便按时间片轮转方式运行。
    • 4)按队列优先级调度。仅当第 1 级队列为空时,才调度第 2 级队列中的进程运行;仅当第 1~ i − 1 i-1 i−1 级队列均为空时,才会调度第 i i i 级队列中的进程运行。若 CPU 正在执行第 i i i 级队列中的某进程时,又有新进程进入任一优先级较高的队列,此时新进程将立即抢占正在运行的进程并回到第 i i i 级队列的末尾,而将 CPU 分配给新到的高优先级进程。
  • 多级反馈队列的优点有以下几点:

    • 1)终端型作业用户:短作业优先。
    • 2)短批处理作业用户:周转时间较短。
    • 3)长批处理作业用户:经过前面几个队列得到部分执行,不会长期得不到处理。

8. 基于公平原则的调度算法

  • 前面介绍的几种调度算法都只能保证满足要求的进程优先运行,但不能保证进程占用了多少 CPU 时间,也未考虑调度的公平性。
  • 本节介绍两种相对公平的调度算法。
(1)保证调度算法
  • 保证调度算法向用户做出明确的性能保证,而非优先运行保证。

  • 一种很实际、很容易实现的保证是:若系统中有 n n n 个用户登录,则每个用户都保证获得 1 / n 1/n 1/n 的 CPU 时间;又如,若在单用户系统有 n n n 个进程正在运行,则每个进程都保证获得 1 / n 1/n 1/n 的 CPU 时间。

  • 为了实现保证调度,系统必须具有下列功能:

    • 1)跟踪各个进程自创建以来已获得了多少 CPU 时间。
    • 2)计算各个进程应该获得的 CPU 时间,即自创建以来的时间除以 n n n。
    • 3)计算各个进程真正获得的 CPU 时间和应获得的 CPU 时间之比。若比率为 0.5,则说明一个进程只获得了应得时间的一半,而若比率为 2.0,则说明它获得了应得时间的 2 倍。
    • 4)调度比率最小的进程持续运行,直到该进程的比率超过最接近它的进程比率为止。
(2)公平分享调度算法
  • 保证过程公平,但并不意味着对用户也公平。

  • 假设各个用户所拥有的进程数不同,如用户 1 启动 4 个进程而用户 2 只启动 1 个进程,采用 RR 调度,那么对每个进程而言很公平,用户 1 得到 80% 的 CPU 时间,而用户 2 只得到 20% 的 CPU 时间,显然对用户 2 有失公平。

  • 公平分享调度算法保证所有用户能获得相同的 CPU 时间,或所要求的时间比例。

  • 在这种方式下,不论用户启动多少进程,都能保证每个用户分配到应有的 CPU 份额。

  • 例如,系统中有两个用户,用户 1 有 4 个进程 A、B、C 和 D,而用户 2 只有 1 个进程 E。

c 复制代码
若采用 RR 调度,为保证两个用户获得相同的 CPU 时间,一个满足条件的调度序列是:
A E B E C E D E A E B E C E D E ...
c 复制代码
若用户 1 获得的 CPU 时间是用户 2 的两倍,则可能的调度序列是:
A B E C D E A B E C D E ...

下表总结了几种常见进程调度算法的特点

先来先服务 短作业优先 高响应比优先 时间片轮转 多级反馈队列
能否可抢占 可以 可以 队列内算法不一定
优点 公平,实现简单 平均等待时间、平均周转时间最优 兼顾长短作业 兼顾长短作业 兼顾长短作业,有较好的响应时间,可行性强
缺点 不利于短作业 长作业会饥饿,估计时间不易确定 计算响应比的开销大 平均等待时间较长,上下文切换浪费时间 最复杂
适用于 批处理系统 分时系统 相当通用
[几种常见进程调度算法的特点]

2.2.6 多处理机调度

  • 多处理机系统的调度较单处理机系统复杂,它与系统结构有关。

  • 非对称多处理机(Asymmetric Multiprocessing,AMP)大多采用主从式操作系统,内核驻留在主机上,而从机上只运行用户程序,进程调度也由主机负责。当从机空闲时,便向主机发送一条请求进程的信号,在主机上有一个就绪队列,只要队列不为空,主机便从队首摘下一个进程分配给索求进程的从机。这种分配方式实现简单,缺点是主机太忙,容易成为系统瓶颈。

  • 对称多处理机(Symmetric Multiprocessing,SMP)的所有处理机都是相同的,因此由调度程序将任何一个进程分配给任何一个 CPU。

  • 本节主要讨论 SMP 系统的调度问题。

1. 亲和性和负载平衡

  • 当一个进程从一个 CPU 移到其他 CPU 上时,应将第一个 CPU 的缓存设置为无效,然后重新填充第二个 CPU 的缓存,这种操作的代价较高。

  • 因此,系统应尽量避免将进程从一个 CPU 移到另一个 CPU,而应尽量让一个进程运行在同一个 CPU 上,这称为处理器亲和性。

  • 对于 SMP 系统,应尽量保证所有 CPU 的负载平衡(也称负载均衡),以便充分利用多处理机的优点。

  • 否则,一个或多个 CPU 会空闲,而其他 CPU 会处于高负载状态,且有一些进程处于等待状态。负载平衡应该设法将负载平均分配到 SMP 系统的所有 CPU 上。

  • 然而,负载平衡通常会抵消处理器亲和性带来的好处。保持一个进程运行在同一个 CPU 上的好处是可以利用它在该 CPU 的缓存。而将进程从一个 CPU 迁移到另一个 CPU 会失去这个好处。因此,在某些系统中,只有当不平衡达到一定程度后才移动进程。

2. 多处理机调度方案

方案一:公共就绪队列
  • 系统中仅设置一个公共就绪队列,所有 CPU 共享同一个就绪队列。

  • 这种方案很好地实现了负载平衡,因为 CPU 一旦空闲,它就立即从公共就绪队列中选择一个进程运行。

  • 缺点是各进程可能频繁地在不同的 CPU 上运行,处理器亲和性不好。

  • 提升处理器亲和性的方法有两种:软亲和和硬亲和。

    • 软亲和是指由调度程序尽量保持一个进程到某个 CPU 上,但这个进程也可以迁移到其他 CPU 上。
    • 硬亲和是指由用户进程通过系统调用,主动请求系统分配到固定的 CPU 上。
  • 例如,Linux 系统实现了软亲和,也支持硬亲和的系统调用。

方案二:私有就绪队列
  • 系统为每个 CPU 设置一个私有就绪队列,当 CPU 空闲时,就从各自的私有就绪队列中选择一个进程运行。

  • 这种方案很好地实现了处理器亲和性,缺点是必须进行负载平衡。

  • 平衡负载的方法通常有两种:推迁移和拉迁移。

    • 对于推迁移,一个特定的系统程序周期性检查每个 CPU 的负载,若发现不平衡,则从超载 CPU 的就绪队列中"推"一些进程到空闲 CPU 的就绪队列,从而平均分配负载。
    • 若一个 CPU 负载很低,则从超载 CPU 的就绪队列中"拉"一些进程到自己的就绪队列,发生拉迁移。
  • 在系统中,推迁移和拉迁移常被并行实现。

参考资料

鲍鱼科技课件

b站免费王道课后题讲解:

网课全程班:

26王道考研书

相关推荐
John.Lewis5 小时前
C++进阶(6)C++11(2)
开发语言·c++·笔记
CheerWWW6 小时前
C++学习笔记——栈内存与堆内存、宏、auto、std::array
c++·笔记·学习
-许平安-7 小时前
MCP项目笔记十(客户端 MCPClient)
c++·笔记·ai·raii·mcp·pluginapi·plugin system
一只旭宝7 小时前
【C++ 入门精讲2】函数重载、默认参数、函数指针、volatile | 手写笔记(附完整代码)
c++·笔记
John.Lewis7 小时前
C++进阶(8)智能指针
开发语言·c++·笔记
weixin_395772478 小时前
计算机网络学习笔记】初始网络之网络发展和OSI七层模型
笔记·学习·计算机网络
小陈phd8 小时前
多模态大模型学习笔记(三十四)——ChatTTS:新一代中文语音合成工具原理与实战解析
笔记·学习·语音识别
码以致用8 小时前
Java垃圾回收器笔记
java·jvm·笔记
zhangrelay8 小时前
面向机器人工程的 Linux 发行版:科学选型与深度评测-2026
笔记·学习