处理机调度算法

原文链接: https://www.jianshu.com/p/1197dc753bbb

调度的概念

       在多道程序系统中,进程的数量往往多于处理机的个数,进程争用处理机的情况就在所难免。 处理机调度是对处理机进行分配,就是从就绪队列中,按照一定的算法(公平、高效)选择一个进程并将处理机分配给它运行,以实现进程并发地执行。

       处理机调度是多道程序操作系统的基础,它是操作系统设计的核心问题。

调度的层次

一个作业从提交开始直到完成,往往要经历以下三级调度,如图所示。

  • 作业调度。又称高级调度 ,其主要任务是按一定的原则从外存上处于后备状态的作业中挑选一个 (或多个) 作业,给它 (们) 分配内存、输入/输出设备等必要的资源,并建立相应的进程,以使它(们) 获得竞争处理机的权利。简言之,就是内存与辅存之间的调度。对于每个作业只调入一次、调出一次。 多道批处理系统中大多配有作业调度,而其他系统中通常不需要配置作业调度。作业调度的执行频率较低,通常为几分钟一次。
  • 内存调度。又称中级调度。引入中级调度是为了提高内存利用率和系统吞吐量。为此, 应使那些暂时不能运行的进程,调至外存等待,把此时的进程状态称为挂起状态 。当它们己具备运行条件且内存又稍有空闲时,由中级调度来决定,把外存上的那些己具备运行条件的就绪进程, 再重新调入内存,并修改其状态为就绪状态 ,挂在就绪队列上等待。
  • 进程调度。又称低级调度,其主要任务是按照某种方法和策略从就绪队列中选取一个进程,将处理机分配给它 。进程调度是操作系统中最基本的一种调度,在一般操作系统中都必须配置进程调度。进程调度的频率很高,一般几十毫秒一次。

处理机调度算法_第1张图片

三级调度的联系

      作业调度从外存的后备队列中选择一批作业进入内存,为它们建立进程,这些进程被送入就绪队列,进程调度从就绪队列中选出一个进程,并把其状态改为运行状态,把CPU分配给它 。中级调度是为了提高内存的利用率,系统将那些暂时不能运行的进程挂起来。当内存空间宽松时, 通过中级调度选择具备运行条件的进程,将其唤醒。

  • 作业调度为进程活动做准备 ,进程调度使进程正常活动起来,中级调度将暂时不能运行的进程挂起,中级调度处于作业调度和进程调度之间。
  • 作业调度改数少,中级调度改数略多,进程调度频率最高。
  • 进程调度是最基本的,不可或缺。

进程调度的时机、切换与过程

        进程调度和切换程序是操作系统内核程序。当请求调度的事件发生后 ,才可能会运行进程调度程序,当调度了新的就绪进程后,才会去进行进程间的切换。理论上这三件事情应该顺序执行, 但在实际设计中,在操作系统内核程序运行时,如果某时发生了引起进程调度的因素,并不一定能够马上进行调度与切换。

现代操作系统 中,不能进行进程的调度与切换的情况有以下几种情况。

  • 1)  在处理中断的过程中:中断处理过程复杂,在实现上很难做到进程切换,而且中断处理是系统工作的一部分,逻辑上不属于某进程,不应被剥夺处理机资源。
  • 2)进程在操作系统内核程序临界区中:进入临界区后,需要独占式地访问共享数据,理论上必须加锁,以防止其他并行程序进入 ,在解锁前不应切换到其他进程运行,以加快该共享数据的释放。
  • 3)其他需要完全屏蔽中断的原子操作过程中:如加锁、解锁、中断现场保护、恢复等原子操作。在原子过程中,连中断都要屏蔽,更不应该进行进程调度与切换。

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

应该进行进程调度与切换的情况有:

  • 1)当发生引起调度条件,且当前进程无法继续运行下去时,可以马上进行调度与切换。如果操作系统只在这种情况下进行进程调度,就是非剥夺调度。
  • 2)当中断处理结束或自陷处理结束后,返回被中断进程的用户态程序执行现场前,若置上请求调度标志,即可马上进行进程调度与切换。如果操作系统支持这种情况下的运行调度程序, 就实现了剥夺方式的调度。

       进程切换往往在调度完成后立刻发生,它要求保存原进程当前切换点的现场信息,恢复被调度进程的现场信息。现场切换时,操作系统内核将原进程的现场信息推入到当前进程的内核堆栈来保存它们,并更新堆栈指针。内核完成从新进程的内核栈中装入新进程的现场信息、更新当前运行进程空间指针、重设 PC 寄存器等相关工作之后,开始运行新的进程。

处理机调度算法_第2张图片

进程调度方式

       所谓进程调度方式是指当某一个进程正在处理机上执行时,若有某个更为重要或紧迫的进程需要处理,即有优先权更高的进程进入就绪队列,此时应如何分配处理机。

通常有以下两种进程调度方式:

1)非剥夺调度方式,又称非抢占方式。是指当一个进程正在处理机上执行时 ,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在执行的进程继续执行,直到该进程完成或发生某种事件而进入阻塞状态时,才把处理机分配给更为重要或紧迫的进程。

      在非剥夺调度方式下,一旦把 CPU 分配给一个进程,那么该进程就会保持 CPU 直到终止或转换到等待状态。这种方式的优点是实现简单、系统开销小,适用于大多数的批处理系统,但它不能用于分时系统和太多数的实时系统。

2)剥夺调度方式,又称抢占方式。是指当一个进程正在处理机上执行时,若有某个更为重要或紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给这个更为重要或紧迫的进程。

      采用剥夺式的调度,对提高系统吞吐率和响应效率都有明显的好处。但 “剥夺” 不是一种任意性行为,必须遵循一定的原则,主要有:优先权、短进程优先和时间片原则等。

典型的调度算法

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

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

  • FCFS调度算法是一种最简单的调度算法,该调度算法既可以用于作业调度也可以用于进程调度。在作业调度中,算法每次从后备作业队列中选择最先进入该队列的一个或几个作业 ,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。
  • 在进程调度中,FCFS调度算法每次从就绪队列中选择最先进入该队列的进程,将处理机分配给它,使之投入运行,直到完成或因某种原因而阻塞时才释放处理机。

       FCFS 调度算法属于不可剥夺算法。 从表面上看 ,它对所有作业都是公平的,但若一个长作业先到达系统,就会使后面许多短作业等待很长时间,因此它不能作为分时系统和实时系统的主要调度策略。但它常被结合在其他调度策略中使用。例如,在使用优先级作为调度策略的系统中, 往往对多个具有相同优先级的进程按 FCFS 原则处理。

       FCFS调度算法的特点是算法简单,但效率低;对长作业比较有利,但对短作业不利(相对SJF 和高响应比);有利于 CPU 繁忙型作业,而不利于I/O繁忙型作业。

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

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

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

  • 1)该算法对长作业不利,严重的是,如果有一长作业进入系统的后备队列,由于调度程序,也是优先调度那些  (即使是后进来的)短作业,将导致长作业长期不被调度(“饥饿” 现象,注意区分 “死锁”,后者是系统环等待,前者是调度策略问题)。
  • 2)该算法完全未考虑作业的紧迫程度,因而不能保证紧迫性作业会被及时处理。
  • 3)由于作业的长短只是根据用户所提供的估计执行时间而定的,而用户又可能会有意或无意地缩短其作业的估计运行时间,致使该算法不一能真正做到短作业优先调度。 

使用抢占式的短作业优先算法又称为最短剩余时间优先算法:每当有进程加入就绪队列时,如果新到达的进程剩余时间比当前运行的进程剩余时间更短,则由新进程抢占处理机,当前进程重新回到就绪队列。

高响应比优先调度算法

       高响应比优先调度算法主要用于作业调度,该算法是对 FCFS 调度算法和 SJF 调度算法的一种综合平衡,同时考虑每个作业的等待时间和估计的运行时间。在每次进行作业调度时 ,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行。

响应比的变化规体可描述为

根据公式可知:

  • 1) 当作业的等待时间相同时,则要求服务时间越短,其响应比越高,有利于短作业。
  • 2) 当要求服务时间相同时,作业的响应比由其等待时间决定 ,等待时间越长,其响应比越高,因而它实现的是先来先服务。
  • 3) 对于长作业 ,作业的响应比可以随等待时间的增加而提高,当其等待时间足够长时,其响应比便可升到很高,从而也可获得处理机。克服了饥饿状态,兼顾了长作业。

时间片轮转调度算法

       时间片轮转调度算法主要适用于分时系统。在这种算法中,系统将所有就绪进程到达时间的先后次序排成一个队列,进程调度程序总是选择就绪队列中第一个进程执行,即先来先服务的原则,但仅能运行一个时间片,如100ms。在使用完一个时间片后,即使进程并未完成其运行 , 它也必须释放出(被剥夺)处理机给下一个就绪的进程,而被剥夺的进程返回到就绪队列的末尾重新排队,等候再次运行。抢占式

       在时间片轮转调度算法中,时间片的大小对系统性能的影响很大。如果时间片足够大,以至于所有进程都能在一个时间片内执行完毕,时间片轮转调度算法就退化为先来先服务调度算法。如果时间片很小,那么处理机将在进程间过于频繁切换,使处理机的开销加大,而真正用于运行用户进程的时间将减少。因此时间片的大小应选择适当 。

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

优先级调度算法

       优先级调度算法又称优先权调度算法,该算法既可以用于作业调度,也可以用于进程调度, 该算法中的优先级用来描述作业运行的紧迫程度。

作业调度中,优先级调度算法每次从后备作业队列中选择优先级最高的一个或几个作业,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。在进程调度中,优先级调度算法每次从就绪队列中选取优先级最高的进程,将处理机分配给它,使之投入运行 。 根据新的更高优先级进程能否抢占正在执行的进程,将该调度算法分为 :

  • 1)非抢占式优先级调度算法。当某一个进程正在处理机上运行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在运行的进程继续运行 ,直到由于其自身的原因而主动让出处理机时 (任务完成或等待事件),才把处理机分配给更为重要或紧迫的进程。
  • 2 )抢占式优先级调度算法。当一个进程正在处理机上运行时 ,若有某个更为垂要或紧迫的进程进入就绪队列,则立即暂停正在运行的进程,将处理机分配给更重要或紧迫的进程。

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

  • 1) 静态优先级 。优先级是在创建进程时确定的,且在进程的整个运行期间保持不变 。确定静态优先级的主要依据有进程类型、进程对资源的要求、用户要求。
  • 2) 动态优先级。在进程运行过程中,根据进程情况的变化动态调整优先级。动态调整优先级的主要依据为进程占有 CPU 时间的长短、就绪进程等待 CPU 时间的长短。

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

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

       通过动态调整进程优先级和时间片大小,多级反馈队列调度算法可以兼顾多方面的系统目标。例如,为提高系统吞吐量和缩短平均周转时间而照顾短进程;为获得较好的I/O设备利用率和缩短响应时间而照顾I/O型进程;同时,也不必事先估计进程的执行时间。

处理机调度算法_第3张图片

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

  • 1)应设置多个就绪队列,并为各个队列赋予不同的优先级,第1级队列的优先级最高,第 2级队列次之,其余队列的优先级逐次降低。
  • 2)赋予各个队列中进程执行时间片的大小也各不相同,在优先级越高的队列中,每个进程的运行时间片就越小。 例如,第2级队列的时间片要比第1级队列的时间片长1倍,第 i+1级 队列的时间片要比第i级队列的时间片长1倍。
  • 3)当一个新进程进入内存后,首先将它放入第1级队列的末尾,按FCFS 原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第 2 级队列的末尾,再同样地按 FCFS 原则等待调度执行;如果它在第 2 级队列中运行一个时间片后仍未完成,再以同样的方法放入第 3级队列... 如此下去,当一个长进程从第 1级队列依次降到第 n 级队列后,在第n 级队列中便采用时间片轮转的方式运行。
  • 4)仅当第1级队列为空时,调度程序才调度第 2 级队列中的进程运行;仅当第i-1级队列均为空时,才会调度第i级队列中的进程运行。如果处理机正在执行第i级队列中的某进程时, 又有新进程进入优先级较高的队列(第1 ~( i -1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第 i级队列的末尾,把处理机分配给新到的更高优先级的进程。

多级反馈队列的优势有以下几点。

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

本节的知识架构图如下:

处理机调度算法_第4张图片

管程

        在信号量机制中,每个要访问临界资源的进程都必须自备同步的PV操作,大量分散的同步操作会给系统管理带来麻烦,且容易因为同步操作不当而导致系统死锁。于是便产生了一种新的进程同步工具——管程(Monitors)

管程(Monitors):是一个资源管理模块,其中包含了共享资源的数据结构,以及由对该共享数据结构实施操作的一组过程(方法)所组成的资源管理程序。

管程中包含条件变量,用于管理进程的阻塞和唤醒。其形式为 condition x;对它的操作仅有wait和signal。

  x.wait:正在调用管程的进程因 x 条件需要被阻塞或挂起,则调用 x.wait 将自己插入到 x 条件的等待队列上,并释放管程,直到 x 条件变化。此时其它进程可以使用该管程。

   x.signal:正在调用管程的进程发现 x 条件发生了变化,则调用 x.signal,重新启动一个因 x 条件而阻塞或挂起的进程。(与信号量的signal不同,没有s:=s+1的操作)

个人理解:

  1. 管程相当于把对临界资源的操作封装了起来,当进程要对资源进行操作时,只要调用管程中的方法就可以了,而不用进程自己担心同步和互斥的问题,管程的内部有自己的一套机制进行同步与互斥。
  2. 管程中每次只允许一个进程进入管程。
  3. 当调用管程的进程因为某原因阻塞或者挂起时,把这个原因定义为一个条件变量x。
  4. x.wait操作就是把自己放到一个队列上,这个队列上的进程都是因为x原因而阻塞的。
  5. x.signal操作就是让在x阻塞队列上的一个进程重新启动。

相对形象的比喻:假如一个管程叫ATM(取款机),其包含两个方法:存款和取款,不同的人代表不同的进程,但是ATM只允许一个人在一个时间段中进行操作,当一个人在使用时,其他的人只能wait。此外,一个人如果使用的时间太长也不行,所以需要一个条件变量来约束他。

比如一个人在操作ATM时突然接电话了,没法继续操作,把这个原因记为x,执行x.wait,让他离开ATM机,去接电话的队列中等待。等到打完电话,即调用了x.signal后,他就可以继续操作ATM了(一般令正在操作ATM的人操作完后,他才能重新进去)。

处理机调度算法_第5张图片

 管程类似于Java中的类,管程中的“入口”就类似于Java中的方法(synchronized修饰),是一种对共享资源的一种封装。

你可能感兴趣的:(【操作系统】)