三、处理机调度与死锁

  上一章介绍的进程主要从概念出发,但程序执行终归是动态的。进程如何参与程序的动态执行过程呢?在多道程序下,进程的数量远大于处理机的数量。那如何对进程进行安排(处于就绪状态的进程有好多,选哪些进程给处理机执行),才能达到一些我们期望的指标(系统吞吐率,资源利用率,响应的及时性)?而这一切的实现很大程度取决于处理机调度性能的好坏。
  从内容上说,本章大体可以分为三个部分:CPU调度、实时调度、死锁。下面让我们一一介绍下吧!

  一、 CPU调度

  一个程序从最开始在内存中到最后执行完毕经历了一段过程。从调度角度上来看,经过了三个调度阶段。分别是高级调度、中级调度、低级调度

  高级调度/长程调度/作业调度

  高级调度指从外存中选出若干作业,为它们分配进程,并改变进程的状态为就绪状态

  低级调度/进程调度/短程调度

  低级调度指在就绪队列中选择一个进程为它提供处理机资源

  中级调度/内存调度

  中级调度的目的是提高内存利用率和系统吞吐率。方式是将内存中暂时不能运行的进程放到外存中(俗称挂起)。当具备运行条件后再由中级调度重新调入内存。
  大致顺序就是高级调度->低级调度->(中级调度)->执行结束。由于分时特点,低级调度可能要多次。
  衡量处理机调度算法的好坏有几个指标,也是目标。优化这些目标就是我们的目的。

  周转时间

  周转时间指从作业被提交给系统开始,到作业完成为止的这段时间间隔。包括下图四个部分:
在这里插入图片描述

  平均周转时间

  平均周转时间就是所有作业的周转时间之和除以作业个数

  带权周转时间

  带权周转时间指周转时间除以执行时间。执行时间就是结束时间减去开始时间

  概念比较抽象,下面结合一个例题看看:
在这里插入图片描述
  以作业二为例,计算它的周转时间,带权周转时间
  周转时间是完成时间-提交时间 是13.00-10.10=2.9
  带权周转时间是周转时间/执行时间,执行时间是完成时间-开始时间=13.00-12.00 = 1。带权周转时间 = 2.9/1 = 2.9。
  同理计算作业1,3的周转时间求和再除以三,就得到平均周转时间了。简不简单!

  说别的都没用,好坏还是要看调度算法怎么样。下面就介绍一下6种调度算法:

  先来先服务调度算法(FCFS, first come first serve)

  这种是最容易实现的算法,先到先执行。那我们来评价一下这个算法的性能:
在这里插入图片描述
  上图有四个作业,A,B,C,D依次到达。直接看性能(带权周转性能),A,B,D都可以看,但C有点儿惨。但实际上C执行的时间相当短,这就是因为C在B这个很长的任务后面。导致周转时间特别长,远超执行时间。这种算法对短任务很不友好,短任务在长任务前面执行还好,但在后面性能就会特别差。

  短作业优先调度算法

  (1) 最短作业优先

  这种算法就有优先级存在了,作业越短优先级越高。这就保证了短任务都能先执行。举个例子,说明执行过程:
在这里插入图片描述
  假设它们都是同一时间到达,burst time是执行时间。按照最小原则,执行顺序依次是4,  1,3,2。从直观上感觉,这个性能应该比FCFS好点儿。但这个算法有一个很难搞的问题:我怎么知道一个进程会执行多长时间呢?所以要用这个,就必须去估算一下,而且误差还不能太大。

  (2) 最短剩余时间优先

  这个和最短作业优先很像,是它的抢占式版本。抢占的依据就是正在执行的进程A剩余时间比新来的进程B整个时间还要长。这种思想也很好理解,假如B一直没有来,A作为唯一进程执行,执行一旦开始就会直至结束。如果A很长,B很短的话,B来了也不能执行,有点儿退化成了FCFS。最短剩余时间每时每刻都检查进程的剩余时间来决定分配。用例子说明下:
在这里插入图片描述
  0时刻,P1到达执行P1。1时刻P2到达,P2是4,P1是7,优先P2。2时刻到达,P1是7,P2是3,P3是9,继续P2,3时刻仍是P2最小。P2执行完选最小的是P4的5,P4结束后再进行P1的7,再P3的9。画出图来,就是这样:
在这里插入图片描述
  这个算法也有缺陷,也要执行程序的执行时间。不过性能和最短作业相比要好。

  优先级调度算法

  (1) 普通优先级调度

   其实前几种方法已经体现了优先级思想,就是时间越少,优先级越高。但这算法中显式的给出优先级,于是进程就按照优先级执行就行了。

  (2) 高响应比优先级调度

   不过前一种方法存在一个问题,优先级是怎么确定呢?确定会不会不公平呢?所以高响应比算法用相应比去评价优先级:
在这里插入图片描述
  当使用响应比以后,就比较公平啦!这样的优点是兼顾了长短进程,但计算优先权也要一点儿额外开销。

   轮转调度算法

   轮转调度有点儿像分时复用,把处理机分很多个时间片。均匀的分给所有进程,这就保证了所有进程都能够得到执行。这种方法问题就是时间片的大小不好确定,时间太长变成了先到先服务,时间太短来回上下文切换频次太高,不值当!

   多级队列调度

  多级队列的思想是针对于不同进程的不同需求,对于交互进程希望响应时间短(且不管是否执行完,但要开始执行),比较适合轮转调度。但后台的批处理(数值计算),一直算就行,只要保证能够执行就可以,就可以用FCFS。所以这里的多级队列就是将就绪队列分成多个队列,不同队列根据需求使用不同算法。

   多级反馈队列调度

   多级反馈队列就是在多级队列基础上改进了一下,增强了动态性。使用多级队列(不同队列可以不同算法),如果进程在第一级没有得到处理,就到第二级。。。以此类推,直到执行为止。
在这里插入图片描述

  二、实时调度

   对于实时调度其实不是课程的重点,但在嵌入式操作系统中都是实时调度。还是有必要简单了解下滴。那啥叫实时调度呢?来一个引入:
在这里插入图片描述
  在这个系统中,周期是50ms,而每次处理时间10ms,如果对于5个任务来说可以执行(相邻执行时间满足最大间隔要求),但如果是6个任务的话,任务A第一次执行和第二次执行间隔60ms,超过了50ms的周期,没法完成调度了。所以系统是否能够进行实时调度,是有条件的,就是:
在这里插入图片描述
  概念是概念,具体的调度过程是由算法决定的,下面就介绍一下常用的实时调度算法:

  最早截至时间优先(EDF, earliest deadline first)

   这个算法思想很简单,就是按照截至时间来决定优先级。越早截至,优先级越高。举个例子:
在这里插入图片描述
  这个例子中,任务到达都是在进程执行中。在非抢占式情况下是没影响的。截至时间依次是1342,所以任务执行顺序也就是1342。

  最低松弛度优先(LLF, least laxity first)

   这个需要先解释啥什么叫松弛度,可以理解成该任务为保证完成最晚从哪里开始到当前的长度。选短的(最紧迫)执行。这个理解比较抽象,举个例子:
在这里插入图片描述
  进程A1执行截至时间是20,进程B1截至时间是50,A1执行时间是10,B1执行时间是25。那A1松弛度为10,B1松弛度为25。A1优先执行。A1到10的时候执行结束,其他任务还没到,B1开始执行。到20时,A2到达,A2截至时间为40,执行时间为10,松弛度为10(30必须开始)。B1松弛度为15(已经执行了10,还有15,50-15-20=15)优先执行A2,依次类推,最终执行结果图如下:
在这里插入图片描述

  三、死锁

   前面陆续地介绍过了死锁,死锁一种现象。会让程序运行终止,系统资源利用率降低。这节中更为详细的介绍一下死锁,并给出一些死锁的解决办法。
   了解了死锁的含义,但也不知道怎么描述,下面给一个具体定义:如果一组进程中每个进程都在等待只有组内其他进程才能引发的事件,就称这一组进程处于死锁状态。有个问题来了,如何避免死锁呢?其实死锁发生需要一些条件,如果我们能避免这些条件,那不就可以解除死锁了吗!我们称这些条件为必要条件:
在这里插入图片描述
  对死锁的解决还有三个策略:
在这里插入图片描述
  比较有意思的是,课程主要讲了前两种策略,但实际应用过程中第三种更为广泛。但对于第三种也没有深刻探究,还是就介绍下学过的吧!

   预防策略

   之前说要破坏条件,那上面介绍了四个条件。互斥条件是不可避免的(因为互斥是为了保证进程之间有效运行的必要条件,所有进程的执行都需要满足互斥,不能为了这个不管那个)
   另外三种都有一些方法(直接截图介绍了):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

   避免策略

   为什么要提出避免策略呢?是因为预防策略过于保守(怎么理解?预防策略解决问题的方式是直接不让问题发生,这显然是一种方法,但过程过于绝对,可能带来一些其他的影响。更优的策略显然是可以让问题发生,并进而想方法解决问题。这就是避免策略!)避免 策略有一些新规定:
在这里插入图片描述
  简单来说,避免策略的思想就是,如果一个操作会让安全状态变成不安全状态,那么就不执行这个操作。那如何判定呢?不能每次都靠看啊。下面就介绍一个专门用来判断的算法:银行家算法。
   银行家算法的思想是找到一个正确的就是正确的,找不到正确的就是错误的。算法的描述如下:
  有四个变量:
  Available:当前系统中可以进行分配的资源数
  Max:各进程所需要的最大资源数
   Allocation:各进程已经分配的资源数
   Need:各进程还需要的资源数 Need = Max – Allocaiton

   计算完四个变量后,就需要对操作进行判断。有几个步骤:
  1. 首先将进程请求设为变量request,如果requset小于need,跳转2。否则认为出错,因  为要求值超过宣布的最大值。
  2. 然后判断request是否小于available,满足到3,否则说明进程目前没有足够资源
  3. 试探将资源进程分配,然后启用安全策略进行判断。

  完成上面这些已经差不多一半儿了!下面看看安全性算法吧:
在这里插入图片描述
  结合一个具体的例子看下:
在这里插入图片描述
  按照上面的算法,其中变量的变换过程如下图:
在这里插入图片描述
  第三章打板儿,继续学习,继续加油吧!

因作者水平有限,如有错误之处,请在下方评论区指出,谢谢!

Supongo que te gusta

Origin blog.csdn.net/gls_nuaa/article/details/117757792
Recomendado
Clasificación