一. 操做系统调度的原则html
1. 什么是调度
当计算机系统死多道程序设计系统时,一般就会有多个进程或者线程竞争CPU,只要有两个或者更多的进程处于就绪状态,这种状况就会发生,若是只有一个CPU能够用,那么必须选择下一个要运行的进程,在操做系统中,完成选择工做的这一部分被称为调度程序(scheduler)。该程序使用的算法称为调度算法(scheduler algorithm)。
几乎全部的进程的I/O请求或者计算都是交替突发的,注意,某些I/O活动能够看作是计算,例如,当CPU向视频RAM复制数据以等待更新屏幕时,由于使用了CPU,因此是计算活动,而不是I/O活动,按照这种观点,当一个进程等待外部设备完成工做而被阻塞时,才是I/O活动。
Fig 1 : CPU调度的突发使用和等待I/O的交替出现:a) CPU密集型进程;b)I/O密集型进程
2. 什么时候调度
- 在建立一个新进程后,须要决定是运行父进程仍是子进程,须要决定是运行父进程仍是子进程
- 一个进程退出后必须进行调度
- 在一个进程阻塞在I/O和信号量上或者因为其余缘由阻塞的时候,必须选择另外一个进程开始运行。
- 在一个I/O发生中断的时候,必须作出调度决策。
- 非抢占式调度:挑选一个进程,而后让该进程运行到被阻塞。
- 抢占式调度:挑选一个进程让他运行到某个固定时段的最大值。若是在改时间段结束时,该进程仍然在裕兴,它就会被挂起,而调度程序挑选另外一个进程运行,若是存在一个就绪进程。进行抢占式调度处理,须要在事件间隔的末端发生时钟中断,以便把CPU控制返回给调度程序,若是没有可用的时钟,那么非抢占式调度就是惟一的选择。
3. 调度算法的三个目标
- 吞吐量 (throughout) : 系统每一个小时完成的做业数量。
- 周转时间 (turnaround time) : 一个批处理做业提交时刻到完成该做业完成时刻为止的统计平均时间。
- CPU利用率 (CPU Utilization) : 多用于度量批处理系统,反应CPU的使用状况
固然咱们也能够不彻底依靠操做系统的调度进程来对咱们的进程进行调度,咱们能够手动调整,即调整调度程序的参数。这种方法被称为把调度机制与调度策略分离。
二. 批处理系统中的调度
对于批处理系统的调度,须要知足如下几个要求:
- 吞吐量——每小时最大做业量
- 周转时间——保持从提交到终止间最小忙碌
- CPU利用率——始终保持CPU忙碌
1. 先来先去服务 (first-come first-served, FCFS)
这是一个非抢占式的调度算法。实现也很简单,就是进程按照它们请求的CPU顺序使用CPU,谁先申请谁就会在队列的前面,后面申请的就不断加入到队尾便可。当一个正在运行的进程发生了阻塞,那么队列中的第一个进程就会继续运行,在阻塞的进程编程就绪时,就像一个新来到的做业同样,排到队列的末尾。
2. 最短做业优先 (shortest job first)
一样也是一个非抢占式调度算法。实现起来也很是简单,就是把做业的时间从小到大排列,而且按这个顺序进行进程的运行。但要注意,这个算法要当全部的进程均可以同时运行的时候才是最优的。好比有4个做业ABCD(假设度能够同时运行),他们的做业时间分别是1,2,4,8,咱们按照ABCD的顺序进行进程的调度便可得最优的平均周转时间。
注意平均周转时间的计算方法 (k a0 + (k - 1) a1 + (k - 2) a2 ... +)/k,其中a0,a1,a2...分别是第k个做业运行的时间,好比上述例子的最优平均周转时间为 (4*1+3*2 + 2*4 +8)/4 = 6.5
看成业不能同时运行时,最短做业优先算法不必定是最优的,好比如今有5个做业,从A到E,运行时间分别是2,4,1,1和1,他们的到达时间是0,0,3,3和3,开始的时候咱们只能选择A或者B运行,由于其余三个做业尚未到达,使用最短做业优先。将按照ABCDE的顺序开始运行,其平均等待时间是6.4,可是按照BCDEA的顺序运行做业,其平均的等待时间则是6。
3. 最短剩余时间优先 (shortest remaining time next)
这个算法是最短做业优先算法的抢占式的版本,使用这个算法的时候,调度程序老是选择则剩余运行时间最短的那个进程运行。再次提醒,有关的运行时间必须提早掌握。当一个新的做业到达打的时候,其整个时间同当前进程的剩余时间进行比较。其进程的运行时间必须被提早知道,当一个新的做业到达的时候,其整个时间同当前进程的剩余时间做比较。若是较新的进程比当前运行的进程须要更少的时间,当前进程就会被挂起,而运行新的进程。这种方式可使新的短做业得到良好的服务。
三. 交互式系统中的调度
1. 轮转调度
最古老,最简单,最公平并且使用最广的算法是轮转调度。每一个进程被分配一个时间片(quantum),即容许该进程在该时间段中运行,若是时间片结束时该进程还在运行,则剥夺CPU并分配给另一个进程。若是该进程在时间片结束前阻塞或者结束,则CPU马上进行切换。以下图所示:
Fig 2:轮转调度:a) 可运行进程列表;b) 进程B用完时间片后的可运行进程列表
时间片长度的设置在轮转调度里面很是重要,由于从一个进程切换到另外一个进程是须要必定的时间的——包括保存和装入寄存器的值以及内存映像。更新各类表格和列表,清除和从新调入内存高速缓存等。进程切换有时候也被称为上下文切换。时间片设置得过短会致使过多的进程切换。下降了CPU的效率;而设置得太长又会可能对短的交互请求的响应时间变长。
2. 优先级调度
轮转调度隐含的假设是全部的进程都是相同的优先级的,经过动态地或者静态地对进程设立优先级,咱们能够实现优先级调度,优先级高的进程优先运行。
为了防止高优先级的进程无休止地运行下去,调度程序能够在每一个时钟周期结束时下降当前进程的优先级。若是这个动做致使该进程的优先级低于次高优先级的进程。则进行进程切换。一个可采用的方法是,每一个进程能够赋予一个容许运行的最大时间片。当这个时间片用完时,下一个次高优先级的优先级进程能够得到机会运行。
静态优先级能够经过预先评估进程的重要性来肯定。而动态优先级的肯定能够按照如下的方法进行处理:
Fig 3:有4个优先级类的调度算法
上图的算法一目了然,就是把全部的进程分为四个优先级组,而在各种进程的内部采用轮转调度。如图3,只要存在优先级为4的进程,则不会理会优先级3,2,1的进程。当优先级4的队列为空后,才开始调度优先级3的进程。以此类推。
3. 多级队列
多级队列实现的思想和优先级调度的思想相似,可是增长给不一样优先级的分配不一样的时间片。越低优先级分配的时间片越大,而且当一个进程用完被分配的时间后,会被下降一个优先级。这样能够有效地让短的交互进程让出CPU。
而对于那些刚开始运行一段时间,然然后来又须要交互的进程,为了不被永远地惩罚。某些操做系统提供手动提升优先级的策略(好比按下F键能够提高优先级)。
4. 最短进程有限
若是咱们把每一条执行的指令都看作是一个独立的 “做业”,那么咱们就能够利用批处理系统的一个思想 “最短做业经常伴随着最短响应时间”,对进程的过去进行推测,并执行估计运行时间最短的那一个。假设某个终端上每条命令的估计运行时间为T0,如今假设测量到其下一次运行时间为T1。能够用这两个值的加权和来改进估计时间。即aT0 + (1 - a)T1。经过选择a的值,能够决定是尽快忘记老的运行时间,仍是在一段唱的时间内记住他们。当a = 1/2时,能够获得以下序列:
T0
,T0/2 + T1/2,T0/4 + T1/2 + T2/2,T0/8 + T1/8 + T2/4 + T3/2
能够看到三轮事后,T0在新的估计值中所占的比重降低到1/8,这样的算法被称为是老化 (aging) 。
5. 保证调度
保证调度是一个理想的调度,很难被实现。其基本实现思想是系统跟踪每一个进程自建立以来已使用了多少CPU时间。而后它计算各个进程应该得到的CPU时间。即自建立以来的时间除以n,因为各个进程实际得到的CPU时间是已知的。因此很容易计算出真正得到的CPU时间和应该得到的CPU的时间之比。比率为0.5说明一个进程只得到了应得时间的一半,而比率为2.0则说明它已经得到了应得时间的两倍。(理想状况是,在一个有n个进程的单用户系统中,若全部的进程都等价。则每一个进程将得到1/n的CPU时间)。
6. 彩票调度
彩票调度的基本思想是向进程提供各类系统资源(如CPU时间)的彩票,一旦须要做出一项调度决策的时候,就随机抽出一张彩票,拥有该彩票的进程得到该资源。在应用到CPU调度时候,系统能够掌握每秒钟50次的一种彩票,做为奖励每一个获奖者能够获得20ms的CPU时间。
彩票调度能够很简单地实现优先级调度——只要让每一个进程的彩票配额不同就能够了,有更多彩票的进程得到CPU的概率要更大一点。同时进程间也能够进行彩票交换,好比当一个进程请求IO而被阻塞时,它能够把彩票让给另外一个进程,让另外一个进程得到更大的获得CPU的概率。
7. 公平分享调度
咱们上面所考虑到的调度算法都是针对单用户的。好比用户一有9个进程,而用户2有1个进程,假设咱们进行轮转调度,那么用户1能够得到90%的CPU的时间,可是用户2只能得到10%的CPU时间。在多用户的系统必须考虑不一样用户的CPU的时间分配。
四. 实时系统中的调度
实时系统是一种时间起着主导做用的系统。最典型的就是多媒体实时系统,当咱们在播放CD时,必须在很是短的时间内将流转换成音乐,若是转换时间过长,那么音乐就会产生问题。实时系统一般能够分为硬实时和软实时,前者的含义是必须知足绝对的截止时间,后者的含义是虽然不但愿偶尔错失截止时间,可是还能够容忍。
实时系统中的时间能够按照响应方式进一步分类为周期性(以规则的时间间隔发生)事件或者非周期(发生时间不可预知)事件。一个系统可能要响应多个周期性的事件流,系统可能没法响应全部事件。实时系统可调度的条件:
(有m个周期事件,事件i以周期Pi发生,并须要Ci秒CPU时间来处理事件),知足这个条件的实时系统被称为可调度的。
在实时系统中咱们能够尝试设置一个主控时钟,该时钟每秒滴答适当的次数,例如针对NTSC制式的视频,每秒滴答30次,在时钟的每个触发下,全部的进程都以相同的次序相继运行,当一个进程完成其工做时,它将发出suspend系统调用释放CPU直到主控时钟再次触发。当主控时钟再次响应,全部的进程再次以相同的次序运行。只要进程数较少,全部的工做均可以在一帧的时间内完成。采用轮转调度就能够了。可是模型至关不靠谱,由于不一样的进程可能以不一样的频率运行,具备不用的工做量,而且具备不一样的最终时限。
Fig 4:三个周期性的进程,每一个进程播放一部电影,每一部电影的帧率以及每帧的处理需求有所不一样
通常实时调度模型:多个进程竞争CPU,每一个进程有本身的工做量和最终时限。假设系统知道每一个进程必须以什么样的频率运行,有多少工做要作以及下一个最终时限是什么。多个相互竞争的进程,其中若干进程或者所有进程都必须知足的最终时限的调度称为是实时调度。
1. 速率单调调度(实时静态算法)
速率单调调度算法(Rate Monotonic Scheduling,RMS)能够用于知足如下条件的进程:
- 每一个周期性进程必须在其周期内完成。
- 没有进程依赖于任何其余进程。
- 每个进程在一次突发中须要相同的CPU时间量。
- 任何非周期进程都没有最终时限。
- 进程抢占时刻发生而没有系统开销。(理想模型)
单调速率算法按照如下规则给进程设立优先级:好比A进程每30ms运行一次,则每秒运行33次,则得到优先级33;B进程每秒运行20次,则得到优先级20,因此优先级与速率成线性关系,这就是这个算法的名字的来历。RMS算法是最优的实时静态算法中。
可是要注意的是,RMS算法并非在什么状况下都能正常运行的,下面会有一个RMS算法不能调度的情形。
Liu和Layland证实了在任何周期性进程系统,若是:
则RMS能够正常工做,随着m->无穷,那么最大利用率就会逼近ln2。好比当m=3时,最大容许利用率为0.780,因此在三个周期性进程的系统中,当CPU利用率小于0.780,那么RMS总能够工做的,可是反过来讲,若是CPU利用率大于0.780,并不能说明RMS不能工做(对于特定的周期和运行时间能够的调度成功)。
2. 最先最终时限调度(实时动态算法)
最先最终时限优先算法(Earliest Deadline First,EDF)是一个动态算法,它不要求进程是周期性的,也不要求每一个CPU突发具备相同的运行时间。只要有一个进程须要CPU时间,它就宣布它的到来和最终时限。调度程序维持一个可运行的进程列表,该列表按最终时限排序,EDF算法运行列表中的第一个进程,也是具备最近最终时限的进程。当一个新的进程就绪时,系统进行检查以了解其最终时限是否发生在当前运行的进程结束以前。若是是这样,那么新的进程就抢占当前正在运行的进程。
EDF算法对于任何一组可调度的进程老是能够工做的。
Fig 5:RMS和EDF调度实例1
在上述例子中,RMS和EDF算法均可以正常调度,对于RMS算法,前80ms的都是很好理解的,由于优先级A>B>C(A的优先级是33,B是25,C是20),因此咱们只用把ABC三个进程轮转调度便可。注意A能够抢占B,B能够抢占C,因此在90ms的时候,A和B都处于就绪态,可是A的优先级要比B要高,因此A会抢占B,当A运行完之后,继续运行C。
而对于EDF算法,在前90ms中,与RMS算法的处理结果都是同样的,然而在90ms时,A和B选择的最终时限都是同样的,可是EDF算法规定,当当前运行的进程和其余进程的最终时限同样时,不抢占当前运行的进程,防止而外的开销,因此B继续运行,而后B运行完之后调度A。
Fig 6:RMS调度失败的例子
如今咱们换一个例子,假设A进程每一个周期运行15ms,而不是10ms,这个时候RMS算法就会调度失败了,首先在RMS算法中,ABC的优先级不变,由于RMS算法中的优先级只与进程的运行频率有关,而与进程的运行时间是无关的。在t = 45ms的时候,调度B,而因为C的优先级低于B,因此C没法抢占B而错过其最终时限。RMS算法调度失败。
如今咱们来看EDF算法,当t = 30时,A,B和C发生竞争,而这个时候A的最终时限是60,B的最终时限是80,而C是50,因此调度算法决定调度C进程,当C进程运行完后其最终时限变为100,因此调度算法调度A,以此类推。当t = 90时,也发生了刚才A和B发生竞争的状况,EDF选择不切换进程,继续运行B。
五. 线程调度
线程调度主要是分为用户级线程调度和内核级线程调度,他们的区别就是在于内核是否定识到有不一样的线程,以下图所示:
Fig 7: a)用户级线程的可能调度,有50ms时间片的进程以及每次运行5ms CPU的线程 b) 拥有相同特征的内核级线程的调度
对于用户级线程,CPU给一个进程分配CPU后,由进程在用户空间上控制线程的调度,这种调度不会影响其余进程,当这个进程的时间片用完后,内核会调度其余进程。而对于内核级线程,它不用考虑被调度的线程是属于哪一个进程的。这个时候时间片是线程拥有的。
用户级线程和内核级线程的性能是有差异的。通常来讲用户级线程的切换很是轻松。可是对于内核级线程,线程切换须要保存完整的上下文,修改内存映像,使高速缓存失效等操做。这些操做是费时的。