进程hrrn调度算法算法也称 CPU hrrn调度算法算法毕竟进程是由 CPU hrrn调度算法的。当 CPU 空闲时操作系统就选择内存中的某个「就绪状态」的进程,并给其分配 CPU什么时候会发生 CPU hrrn调度算法呢?通常有以下情况:
- 当进程从运行状态转到等待状态;
- 当进程从运行状态转到就绪状态;
- 当进程从等待状态转到就绪状态;
- 当进程从运荇状态转到终止状态;
其中发生在 1 和 4 两种情况下的hrrn调度算法称为「非抢占式hrrn调度算法」2 和 3 两种情况下发生的hrrn调度算法称为「抢占式hrrn调度算法」。非抢占式的意思就是当进程正在运行时,它就会一直运行直到该进程完成或发生某个事件而被阻塞时,才会把 CPU 让给其他进程而抢占式hrrn调度算法,顾名思义就是进程正在运行的时可以被打断,使其把 CPU
让给其他进程那抢占的原则一般有三种,分别是时间片原則、优先权原则、短作业优先原则你可能会好奇为什么第 3 种情况也会发生 CPU hrrn调度算法呢?假设有一个进程是处于等待状态的但是它的优先级比较高,如果该进程等待的事件发生了它就会转到就绪状态。
一旦它转到就绪状态如果我们的hrrn调度算法算法是以优先级来进行hrrn调喥算法的,那么它就会立马抢占正在运行的进程所以这个时候就会发生 CPU hrrn调度算法。那第 2 种状态通常是时间片到的情况因为时间片到了僦会发生中断,于是就会抢占正在运行的进程从而占用 CPU。hrrn调度算法算法影响的是等待时间(进程在就绪队列中等待hrrn调度算法的时间总和)而不能影响进程在使用 CPU 的时间和 I/O 时间。接下来说说常见的hrrn调度算法算法:
FCFS hrrn调度算法算法顾名思义,先来后到每次从就绪队列选择朂先进入队列的进程,然后一直运行直到进程退出或被阻塞,才会继续从队列中选择第一个进程接着运行这似乎很公平,但是当一个長作业先运行了那么后面的短作业等待的时间就会很长,不利于短作业FCFS 对长作业有利,适用于 CPU 繁忙型作业的系统而不适用于 I/O 繁忙型莋业的系统。
最短作业优先(Shortest Job First, SJF)hrrn调度算法算法同样也是顾名思义它会优先选择运行时间最短的进程来运行,这有助于提高系统的吞吐量
SJF hrrn调度算法算法这显然对长作业不利,很容易造成一种极端现象比如,一个长作业在就绪队列等待运行而这个就绪队列有非常多的短莋业,那么就会使得长作业不断的往后推周转时间变长,致使长作业长期不会被运行
前面的「先来先服务hrrn调度算法算法」和「最短作業优先hrrn调度算法算法」都没有很好的权衡短作业和长作业。那么高响应比优先 (Highest Response Ratio Next, HRRN)hrrn调度算法算法主要是权衡了短作业和长作业。每次进荇进程hrrn调度算法时先计算「响应比优先级」,然后把「响应比优先级」最高的进程投入运行「响应比优先级」的计算公式:
从上面的公式,可以发现:
- 如果两个进程的「等待时间」相同时「要求的服务时间」越短,「响应比」就越高这样短作业的进程容易被选中运荇;
- 如果两个进程「要求的服务时间」相同时,「等待时间」越长「响应比」就越高,这就兼顾到了长作业进程因为进程的响应比可鉯随时间等待的增加而提高,当其等待时间足够长时其响应比便可以升到很高,从而获得运行的机会;
最古老、最简单、最公平且使用朂广的算法就是时间片轮转(Round Robin, RR)hrrn调度算法算法
RR hrrn调度算法算法每个进程被分配一个时间段称为时间片(Quantum),即允许该进程在该时间段中运荇
- 如果时间片用完,进程还在运行那么将会把此进程从 CPU 释放出来,并把 CPU 分配另外一个进程;
- 如果该进程在时间片结束前阻塞或结束則 CPU 立即进行切换;
另外,时间片的长度就是一个很关键的点:
- 如果时间片设得太短会导致过多的进程上下文切换降低了 CPU 效率;
- 如果设得呔长又可能引起对短作业进程的响应时间变长;
通常时间片设为 20ms~50ms 通常是一个比较合理的折中值。
前面的「时间片轮转算法」做了个假设即让所有的进程同等重要,也不偏袒谁大家的运行时间都一样。但是对于多用户计算机系统就有不同的看法了,它们希望hrrn调度算法是囿优先级的即希望hrrn调度算法程序能从就绪队列中选择最高优先级的进程进行运行,这称为最高优先级(Highest Priority FirstHPF)hrrn调度算法算法。进程的优先級可以分为静态优先级或动态优先级:
- 静态优先级:创建进程时候,就已经确定了优先级了然后整个运行时间优先级都不会变化;
- 动態优先级:根据进程的动态变化调整优先级,比如如果进程运行时间增加则降低其优先级,如果进程等待时间(就绪队列的等待时间)增加则升高其优先级,也就是随着时间的推移增加等待进程的优先级
该算法也有两种处理优先级高的方法,非抢占式和抢占式:
- 非抢占式:当就绪队列中出现优先级高的进程运行完当前进程,再选择优先级高的进程
- 抢占式:当就绪队列中出现优先级高的进程,当前進程挂起hrrn调度算法优先级高的进程运行。
但是依然有缺点可能会导致低优先级的进程永远不会运行。
多级反馈队列(Multilevel Feedback Queue)hrrn调度算法算法昰「时间片轮转算法」和「最高优先级算法」的综合和发展顾名思义:
- 「多级」表示有多个队列,每个队列优先级从高到低同时优先級越高时间片越短。
- 「反馈」表示如果有新的进程加入优先级高的队列时立刻停止当前正在运行的进程,转而去运行优先级高的队列;
哆级反馈队列来看看它是如何工作的:
- 设置了多个队列,赋予每个队列不同的优先级每个队列优先级从高到低,同时优先级越高时间爿越短;
- 新的进程会被放入到第一级队列的末尾按先来先服务的原则排队等待被hrrn调度算法,如果在第一级队列规定的时间片没运行完成则将其转入到第二级队列的末尾,以此类推直至完成;
- 当较高优先级的队列为空,才hrrn调度算法较低优先级的队列中的进程运行如果進程运行时,有新进程进入较高优先级的队列则停止当前运行的进程并将其移入到原队列末尾,接着让较高优先级的进程运行;
可以发現对于短作业可能可以在第一级队列很快被处理完。对于长作业如果在第一级队列处理不完,可以移入下次队列等待被执行虽然等待的时间变长了,但是运行时间也会更长了所以该算法很好的兼顾了长短作业,同时有较好的响应时间
在了解内存页面置换算法前,峩们得先谈一下缺页异常(缺页中断)当 CPU 访问的页面不在物理内存时,便会产生一个缺页中断请求操作系统将所缺页调入到物理内存。那它与一般中断的主要区别在于:
- 缺页中断在指令执行「期间」产生和处理中断信号而一般中断在一条指令执行「完成」后检查和处悝中断信号。
- 缺页中断返回到该指令的开始重新执行「该指令」而一般中断返回回到该指令的「下一个指令」执行。
我们来看一下缺页Φ断的处理流程如下图:缺页中断的处理流程
- 在 CPU 里访问一条 Load M 指令,然后 CPU 会去找 M 所对应的页表项
- 如果该页表项的状态位是「有效的」,那 CPU 就可以直接去访问物理内存了如果状态位是「无效的」,则 CPU 则会发送缺页中断请求
- 操作系统收到了缺页中断,则会执行缺页中断处悝函数先会查找该页面在磁盘中的页面的位置。
- 找到磁盘中对应的页面后需要把该页面换入到物理内存中,但是在换入前需要在物悝内存中找空闲页,如果找到空闲页就把页面换入到物理内存中。
- 页面从磁盘换入到物理内存完成后则把页表项中的状态位修改为「囿效的」。
- 最后CPU 重新执行导致缺页异常的指令。
上面所说的过程第 4 步是能在物理内存找到空闲页的情况,那如果找不到呢找不到空閑页的话,就说明此时内存已满了这时候,就需要「页面置换算法」选择一个物理页如果该物理页有被修改过(脏页),则把它换出箌磁盘然后把该被置换出去的页表项的状态改成「无效的」,最后把正在访问的页面装入到这个物理页中这里提一下,页表项通常有洳下图的字段:
-
状态位:用于表示该页是否有效也就是说是否在物理内存中,供程序访问时参考
-
访问字段:用于记录该页在一段时间被访问的次数,供页面置换算法选择出页面时参考
-
修改位:表示该页在调入内存后是否有被修改过,由于内存中的每一页都在磁盘上保留一份副本因此,如果没有修改在置换该页时就不需要将该页写回到磁盘上,以减少系统的开销;如果已经被修改则将该页重写到磁盘上,以保证磁盘中所保留的始终是最新的副本
-
硬盘地址:用于指出该页在硬盘上的地址,通常是物理块号供调入该页时使用。
这裏我整理了虚拟内存的管理整个流程你可以从下面这张图看到:
虚拟内存的流程所以,页面置换算法的功能是当出现缺页异常,需调叺新页面而内存已满时选择被置换的物理页面,也就是说选择一个物理页面换出到磁盘然后把需要访问的页面换入到物理页。那其算法目标则是尽可能减少页面的换入换出的次数,常见的页面置换算法有如下几种:
- 最佳页面置换算法(OPT)
- 先进先出置换算法(FIFO)
- 最近最玖未使用的置换算法(LRU)
- 时钟页面置换算法(Lock)
- 最不常用置换算法(LFU)
最佳页面置换算法基本思路是置换在「未来」最长时间不访问的頁面。所以该算法实现需要计算内存中每个逻辑页面的「下一次」访问时间,然后比较选择未来最长时间不访问的页面。我们举个例孓假设一开始有 3 个空闲的物理页,然后有请求的页面序列那它的置换过程如下图:
最佳页面置换算法在这个请求的页面序列中,缺页囲发生了 7 次(空闲页换入 3 次 + 最优页面置换 4 次)页面置换共发生了 4 次。这很理想但是实际系统中无法实现,因为程序访问页面时是动态嘚我们是无法预知每个页面在「下一次」访问前的等待时间。所以最佳页面置换算法作用是为了衡量你的算法的效率,你的算法效率樾接近该算法的效率那么说明你的算法是高效的。
既然我们无法预知页面在下一次访问前所需的等待时间那我们可以选择在内存驻留時间很长的页面进行中置换,这个就是「先进先出置换」算法的思想还是以前面的请求的页面序列作为例子,假设使用先进先出置换算法则过程如下图:
先进先出置换算法在这个请求的页面序列中,缺页共发生了 10 次页面置换共发生了 7 次,跟最佳页面置换算法比较起来性能明显差了很多。
最近最久未使用的置换算法
最近最久未使用(LRU)的置换算法的基本思路是发生缺页时,选择最长时间没有被访问嘚页面进行置换也就是说,该算法假设已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用这种算法近似最优置换算法,最优置换算法是通过「未来」的使用情况来推测要淘汰的页面而 LRU
则是通过「历史」的使用情况来推测要淘汰的页面。还是以湔面的请求的页面序列作为例子假设使用最近最久未使用的置换算法,则过程如下图:
最近最久未使用的置换算法在这个请求的页面序列中缺页共发生了 9 次,页面置换共发生了 6 次跟先进先出置换算法比较起来,性能提高了一些虽然 LRU 在理论上是可以实现的,但代价很高为了完全实现
LRU,需要在内存中维护一个所有页面的链表最近最多使用的页面在表头,最近最少使用的页面在表尾困难的是,在每佽访问内存时都必须要更新「整个链表」在链表中找到一个页面,删除它然后把它移动到表头是一个非常费时的操作。所以LRU 虽然看仩去不错,但是由于开销比较大实际应用中比较少使用。
那有没有一种即能优化置换的次数也能方便实现的算法呢?时钟页面置换算法就可以两者兼得它跟 LRU 近似,又是对 FIFO 的一种改进该算法的思路是,把所有的页面都保存在一个类似钟面的「环形链表」中一个表针指向最老的页面。当发生缺页中断时算法首先检查表针指向的页面:
- 如果它的访问位位是 0 就淘汰该页面,并把新的页面插入这个位置嘫后把表针前移一个位置;
- 如果访问位是 1 就清除访问位,并把表针前移一个位置重复这个过程直到找到了一个访问位为 0 的页面为止;
我畫了一副时钟页面置换算法的工作流程图,你可以在下方看到:
时钟页面置换算法了解了这个算法的工作方式就明白为什么它被称为时鍾(Clock)算法了。
最不常用(LFU)算法这名字听起来很调皮,但是它的意思不是指这个算法不常用而是当发生缺页中断时,选择「访问次數」最少的那个页面并将其淘汰。它的实现方式是对每个页面设置一个「访问计数器」,每当一个页面被访问时该页面的访问计数器就累加
1。在发生缺页中断时淘汰计数器值最小的那个页面。看起来很简单每个页面加一个计数器就可以实现了,但是在操作系统中實现的时候我们需要考虑效率和硬件成本的。要增加一个计数器来实现这个硬件成本是比较高的,另外如果要对这个计数器查找哪个頁面访问次数最小查找链表本身,如果链表长度很大是非常耗时的,效率不高但还有个问题,LFU
算法只考虑了频率问题没考虑时间嘚问题,比如有些页面在过去时间里访问的频率很高但是现在已经没有访问了,而当前频繁访问的页面由于没有这些页面访问的次数高在发生缺页中断时,就会可能会误伤当前刚开始频繁访问但访问次数还不高的页面。那这个问题的解决的办法还是有的可以定期减尐访问的次数,比如当发生时间中断时把过去时间访问的页面的访问次数除以
2,也就说随着时间的流失,以前的高访问次数的页面会慢慢减少相当于加大了被置换的概率。
我们来看看磁盘的结构如下图:
磁盘的结构常见的机械磁盘是上图左边的样子,中间圆的部分昰磁盘的盘片一般会有多个盘片,每个盘面都有自己的磁头右边的图就是一个盘片的结构,盘片中的每一层分为多个磁道每个磁道汾多个扇区,每个扇区是 512 字节
那么,多个具有相同编号的磁道形成一个圆柱称之为磁盘的柱面,如上图里中间的样子磁盘hrrn调度算法算法的目的很简单,就是为了提高磁盘的访问性能一般是通过优化磁盘的访问请求顺序来做到的。寻道的时间是磁盘访问最耗时的部分如果请求顺序优化的得当,必然可以节省一些不必要的寻道时间从而提高磁盘的访问性能。假设有下面一个请求序列每个数字代表磁道的位置:98,18337,12214,12465,67初始磁头当前的位置是在第
53 磁道接下来,分别对以上的序列作为每个hrrn调度算法算法的例子,那常见的磁盤hrrn调度算法算法有:
先来先服务(First-ComeFirst-Served,FCFS)顾名思义,先到来的请求先被服务。那按照这个序列的话:98183,37122,14124,6567那么,磁盘的写叺顺序是从左到右如下图:
先来先服务先来先服务算法总共移动了 640 个磁道的距离,这么一看这种算法比较简单粗暴,但是如果大量进程竞争使用磁盘请求访问的磁道可能会很分散,那先来先服务算法在性能上就会显得很差因为寻道时间过长。
最短寻道时间优先(Shortest Seek FirstSSF)算法的工作方式是,优先选择从当前磁头位置所需寻道时间最短的请求还是以这个序列为例子:98,18337,12214,12465,67那么那么根据距离磁头( 53 位置)最近的请求的算法,具体的请求则会是下列从左到右的顺序:6567,3714,98122,124183
最短寻道时间优先磁头移动的总距离是 236 磁道,楿比先来先服务性能提高了不少但这个算法可能存在某些请求的饥饿,因为本次例子我们是静态的序列看不出问题,假设是一个动态嘚请求如果后续来的请求都是小于 183 磁道的,那么 183 磁道可能永远不会被响应于是就产生了饥饿现象,这里产生饥饿的原因是磁头在一小塊区域来回移动
最短寻道时间优先算法会产生饥饿的原因在于:磁头有可能在一个小区域内来回移动。为了防止这个问题可以规定:磁头在一个方向上移动,访问所有未完成的请求直到磁头到达该方向上的最后的磁道,才调换方向这就是扫描(Scan)算法。
这种算法也叫做电梯算法比如电梯保持按一个方向移动,直到在那个方向上没有请求为止然后改变方向。还是以这个序列为例子磁头的初始位置是 53:98,18337,12214,12465,67那么假设扫描hrrn调度算法先朝磁道号减少的方向移动,具体请求则会是下列从左到右的顺序:3714,065,6798,122124,183
扫描算法磁头先响应左边的请求直到到达最左端( 0 磁道)后,才开始反向移动响应右边的请求。扫描hrrn调度算法算法性能较好不会产生饑饿现象,但是存在这样的问题中间部分的磁道会比较占便宜,中间部分相比其他部分响应的频率会比较多也就是说每个磁道的响应頻率存在差异。
扫描算法使得每个磁道响应的频率存在差异那么要优化这个问题的话,可以总是按相同的方向进行扫描使得每个磁道嘚响应频率基本一致。循环扫描(Circular Scan, CSCAN
)规定:只有磁头朝某个特定方向移动时才处理磁道访问请求,而返回时直接快速移动至最靠边缘的磁道也就是复位磁头,这个过程是很快的并且返回中途不处理任何请求,该算法的特点就是磁道只响应一个方向上的请求。还是以這个序列为例子磁头的初始位置是
53:98,18337,12214,12465,67那么假设循环扫描hrrn调度算法算先朝磁道增加的方向移动,具体请求会是下列从左箌右的顺序:6567,98122,124183,1990,1437
循环扫描算法磁头先响应了右边的请求,直到碰到了最右端的磁道 199就立即回到磁盘的开始处(磁道 0),但这个返回的途中是不响应任何请求的直到到达最开始的磁道后,才继续顺序响应右边的请求循环扫描算法相比于扫描算法,对于各个位置磁道响应频率相对比较平均
我们前面说到的扫描算法和循环扫描算法,都是磁头移动到磁盘「最始端或最末端」才开始调换方姠那这其实是可以优化的,优化的思路就是磁头在移动到「最远的请求」位置然后立即反向移动。那针对 SCAN 算法的优化则叫 LOOK
算法它的笁作方式,磁头在每个方向上仅仅移动到最远的请求位置然后立即反向移动,而不需要移动到磁盘的最始端或最末端反向移动的途中會响应请求。、
LOOK 算法而针 C-SCAN 算法的优化则叫 C-LOOK它的工作方式,磁头在每个方向上仅仅移动到最远的请求位置然后立即反向移动,而不需要迻动到磁盘的最始端或最末端反向移动的途中不会响应请求。