第三章 处理机调度与死锁
学习自《计算机操作系统》第五版
处理机=处理器(cpu)+主存储器+输入输出设备接口
内存中的进程数目往往多于处理机数目,所以需要系统按某种算法,动态地分配处理机给就绪状态的一个进程,分配处理机的任务由处理机调度程序完成。
处理机调度
调度层次
- 高级调度,又称作业调度,调度对象是作业,主要功能是决定将外存上处于后备队列的哪些作业调入内存、为它们创建进程分配资源,并将它们放入就绪队列。(高级调度主要存在于多道批处理系统。)
- 中级调度,又称内存调度,主要目的是提高内存利用率和系统吞吐量。该调度会把那些暂时无法运行的进程调到外存等待,此时被调进程的状态称为就绪驻外存(挂起)状态;当它们符合继续运行的条件而且内存也有足够的空间时会被重新调入内存,此时再调入内存并修改为就绪状态,挂在就绪队列等待,中级调度实质上就是存储器管理中的对换Swap功能。
- 低级调度,又称进程调度,调度对象是进程或者内核级线程,该调度决定就绪队列中的哪个进程应获得处理机,并由分派程序把处理机分配给被选中的进程。进程调度是最基本的调度,即多道批处理、分时、实时系统,都应该配置这类调度。
调度算法的目标
饥饿现象,简单来说就是作业等待时间过长,类似人等待吃饭过久而饥饿
-
处理机调度算法的共同目标
- 资源利用率
- 要提高资源利用率,就要尽可能使CPU处于忙碌状态
- CPU的利用率 = CPU有效工作时间/(CPU有效工作时间+CPU空闲等待时间)
- 公平性
- 所有进程都获得合理的CPU时间,不会发生进程饥饿现象(相对的公平)
- 平衡性
- 策略强制执行
- 资源利用率
-
批处理系统的目标
-
平均周转时间短
-
周转时间即从作业提交到作业完成经过的时间,
-
即 周转时间=结束时间-进入时间,包括四部分:
- 作业在外存后备队列上等待作业调度的时间
- 进程在就绪队列上等待进程调度的时间
- 进程在CPU上执行的时间
- 进程等待I/0操作完成的时间
-
平均周转时间可以表示为:
[T=frac{1}{n}sum_{i=1}^nT_i=frac{总周转时间}{作业数} ]
-
-
-
为了更好地描述调度的性能,往往采用带权周转时间,即周转时间Ti和运行时间Ts的比值,平均带权周转时间可以表示为:
$$
W=frac{1}{n}sum_{i=1}^nfrac{T_i}{T_s}
$$-
系统吞吐量高
- 吞吐量即单位时间系统完成的作业数,显然长度短的作业更容易完成,可以让吞吐量更高
-
处理机利用率高
- 处理机利用率高则要求作业尽可能长,与系统吞吐量高的做法矛盾
-
-
分时系统的目标
- 响应时间快
- 即从用户输入提交一个请求直到得到处理结果为止的时间尽可能短。
- 响应时间包含三部分:
- 从输入请求信息直到其被传送至处理机的时间
- 处理机对请求的处理时间
- 把处理结果回传给用户的时间
- 均衡性
- 系统响应的快慢应与用户请求服务的复杂性相适应
- 响应时间快
-
实时系统的目标
- 截止时间的保证
- 截止时间指某任务必须开始执行的最迟时间或必须完成的最迟时间
- 可预测性
- 在实时系统中很多请求都是可预测的,如视频的播放,如果系统采用双缓冲,则因为可实现第i帧播放和第i+1帧的读取并行处理,从而提高实时性
- 截止时间的保证
作业与作业调度
批处理系统中的作业
作业
- 作业,包含了程序,数据以及作业说明书,系统根据说明书对程序的运行进行控制
- 在批处理系统中,是以作业为基本单位从外存调入内存的
作业步
- 作业运行期间,每个作业需经过一个个相对独立又相互关联的顺序加工步骤才能得到结果,这些加工步骤称为作业步
- 一个典型的作业分成:编译作业步,链接装配作业步,运行作业步
作业控制块(Job Control Block,JCB)
- 为管理和调度作业,每个作业设置了一个作业控制块JCB,其中保存了系统对作业进行管理和调度所需的全部信息,如:作业标识,用户名称,用户账号,作业类型,作业状态,调度信息,资源需求等
- 每当一个作业进入系统,便由作业注册程序建立一个JCB,然后进行管理和调度
作业运行的三个阶段和三种状态
- 收容阶段,对应作业的后备状态,将作业输入到硬盘,再为其建立JCB,并放入作业后备队列
- 运行阶段,对应作业的运行状态,作业被作业调度选中,分配资源建立进程,并放入就绪队列
- 完成阶段,对应作业的完成状态,回收JCB和资源,将结果形成输出文件输出
作业调度主要任务
主要任务是根据JCB中的信息监测资源是否能满足作业的需求,并按照一定的算法从外存后备队列中选取作业进入内存,故其又称接纳调度。每次执行作业调度都需做以下决定
- 接纳多少个作业
- 接纳哪些作业
作业调度算法
-
先来先服务调度算法(First-come First-served,FCFS)
- 最简单的调度算法,既可用于作业调度,又能用于进程调度
- 该算法按作业到达的时间次序进行调度,即等待时间为优先级评判的唯一标准。
-
短作业优先调度算法(Short Job First,SJF)
- 既可用于作业调度,又能用于进程调度
- 该算法按作业长短调度,即作业运行时间为优先级评判的唯一标准,时间越短优先级越高
- 缺点是:
- 必须预知作业多运行时间
- 对长作业不利,完全忽视作业等待时间,可能出现饥饿现象
- 无法优先处理紧迫作业。
-
优先级调度算法(Priority-scheduling Algorithm,PSA)
- 该算法按作业优先级调度,而作业的优先级基于作业的紧迫程度
-
高响应比优先调度算法
-
该算法既考虑作业等待时间,又考虑作业运行时间
-
该算法为每个作业引入一个动态优先级,令它随等待时间增加而优先级提高
[优先权R_p=frac{等待时间+要求服务时间}{要求服务时间}=frac{响应时间}{要求服务时间} ] -
进程调度
进程调度任务
- 保存处理机的现场信息
- 按某种算法选取进程
- 把处理器分配给进程
进程调度机制
- 排队器
- 分派器
- 上下文切换器
进程调度方式
- 非抢占方式
- 一旦把处理机分配给某个进程,就让它一直运行直到其完成,不会因为任何原因去抢占当前正在运行进程的处理机,直至该进程完成或发生某事件而被阻塞,才把处理机分配给其他进程
- 抢占方式
- 调度程序会根据某种原则去暂停某个正在执行的进程,把已分配给该进程的处理机重新分配给其他进程。抢占不是任意性行为,必须遵循一定的原则:
- 优先权原则,即允许优先级高的新进程抢占当前进程的处理机;
- 短进程优先原则,即允许新的短进程抢占当前长进程的处理机;
- 时间片原则,即各进程按时间片轮转运行,当正在执行的进程的一个时间片用完后便停止执行并重新调度。
- 调度程序会根据某种原则去暂停某个正在执行的进程,把已分配给该进程的处理机重新分配给其他进程。抢占不是任意性行为,必须遵循一定的原则:
进程调度算法
-
轮转调度算法(Round Robin,RR)
- 基本原理:系统把所有就绪进程按FCFS排成一就绪队列,并让队首进程轮流出队,把CPU分配给出队进程并让它执行一个时间片。系统可以设置每隔一定时间产生依次中断,以激活调度程序进行重新调度。
- 进程切换时机
- 一个时间片用完之前该进程就已经完成时,立即激活调度程序重新调度,启动一个新时间片
- 一个时间片用完时,计时器中断处理程序会被激活,此时若进程未完成,则会被送入就绪队列尾。
- 时间片大小确定
- 时间片过短则利于短作业,但会频繁地进行进程调度和进程上下文切换,增加系统开销。
- 时间片过长,极端情况下每个进程都能在一个时间片内完成,RR算法也就退化成了FCFS算法。
- 较可取的时间片长度是略长于一次典型交互所需的时间。
-
优先级调度算法
轮转调度算法其实隐含了一个假设:所有进程的紧迫程度相同,但实际并非如此,所以引入了优先级
- 算法类型
- 抢占式优先级调度算法
- 把处理机分配给优先级最高的进程执行,执行期间若出现另一个优先级更高的进程,则将处理机分配给新的进程
- 非抢占式优先级调度算法
- 一旦把处理机分配给优先级最高的进程执行,就一直执行下去直到完成,或因该进程发生某事件放弃处理机时,才能重新分配处理机
- 抢占式优先级调度算法
- 优先级类型
- 静态优先级(优先级数字放于PCB)
- 动态优先级
- 算法类型
-
多队列调度算法
- 把就绪队列拆分为多个,把类型或性质不同的进程分配到不同的就绪队列队列,不同的队列还可以设置不同的优先级,采用不同的调度算法。
-
多级反馈队列调度算法
- 设置多个就绪队列,队列的优先级依次降低,队列优先级越高,其对应的时间片越小。通常某队列的时间片大小是上一队列的两倍。
- 每个队列都采用FCFS算法。新进程进入内存后首先进入第一个队列,按FCFS原则等待调度。若进程可以在一个时间片内完成则撤出,否则把它移入下一个队列队尾等待调度,以此类推。当进程被降至最后一个队列时,则采用RR算法运行。
- 按队列优先级调度,即若要调度第i队列的进程,则要求第1~(i-1)队列都空闲。若某队列的某进程运行时有新的进程进入优先级更高的队列,则需立即把该进程放回队尾,并把处理机分配给新进程。
-
基于公平原则算法
- 保证调度算法
- 保证每个进程都获得同等的处理机时间
- 公平分享调度算法
- 保证每个用户都获得同等的处理机时间
- 保证调度算法
实时调度
实时系统存在两种不同性质的实时任务,即HRT任务和SRT任务,它们都有一个截止时间,为保证系统正常工作,实时调度必须能满足实时任务对截止时间的要求
实现条件
- 提供必要信息
- 就绪时间,开始截止时间和完成截止时间,处理时间,资源要求,优先级
- 系统处理能力强
- 采用抢占式调度机制
- 具有快速切换机制
- 对中断的快速响应能力
- 快速的任务分配能力
实时调度算法的分类
-
根据实时任务性质,可分为硬实时调度算法和软实时调度算法
-
按调度方式可分为
- 非抢占式调度算法
- 非抢占式轮换调度算法
- 非抢占式优先调度算法
- 抢占式调度算法
- 基于时钟中断的抢占式优先级调度算法
- 立即抢占的优先级调度算法
- 非抢占式调度算法
-
最早截止时间优先(Earliest Deadline First,EDF)算法
- 根据任务的截止时间确定优先级,截止时间越早,在队列的位置越靠前,调度程序总是选择队首进程执行。
-
最低松弛度优先(Least Laxity First,LLF)算法
-
根据任务的紧急(松弛)程度确定优先级,紧急程度则根据必须完成时间、运行时间和当前时间综合考量
-
假设一个任务必须在时刻200ms时完成,而执行这个任务需要100ms,则这个任务在0时刻的紧急程度就是100ms,在100ms时刻的紧急程度为0(此时再不执行则无法按时完成)。松弛度的计算为:
[松弛度=必须完成时间−本身运行时间−当前时间 ]
-
优先级倒置
-
形成:由于运行顺序不同,可能高优先级进程/线程被低优先级进程/线程延迟或阻塞
-
例:P1和P3通过共享一个临界资源进行交互,优先级P1>P2>P3
-
解决办法:
- 简单方法:规定进程进入临界区后不能被抢占处理机
- 实用方法:建立在动态优先级继承基础上,当优先级更高的进程或线程B进入相同临界区,原来已经进入临界区的相对优先级低的进程A继承这个B的更高优先级,直到退出临界区
死锁
资源问题
- 可重用性资源(信号量)和可消耗性资源
- 可抢占式资源和不可抢占式资源(信号量)
死锁成因
- 竞争不可抢占资源
- 竞争可消耗资源
- 进程推进顺序不当。
定义:每个进程都在等待
死锁定义
一组进程中的每个进程都在等待仅由该组进程中的其他进程才能引发的事件,则该组进程是死锁的
死锁产生必要条件
无法同时满足这四个条件就不会产生死锁
- 互斥条件:待分配的资源的使用具有排他性
- 请求和保持条件:若进程持有了一个资源的同时又有一个新的资源请求,且该资源已被其他进程占有,此时请求进程被阻塞而已持有的资源又继续保持;
- 不可抢占条件:进程获得的资源在使用完之前不能被抢占,只能在进程使用完时自己释放
- 循环等待条件:存在一个进程——资源的循环链,构成环路等待
处理死锁方法
四种防范程度逐渐减弱
-
预防死锁
提前破坏死锁的必要条件(任意一个)
-
避免死锁
-
检测死锁
-
解除死锁
预防死锁
破坏请求和保持条件
-
第一种协议
所有进程在开始运行之前,必须一次性地获取整个运行过程中所需的全部资源
-
第二种协议
允许一个进程获得初期资源便可开始运行,由于会释放已经用过的资源所以不会死锁
破坏不可抢占条件
当一个已经保持了某些不可被抢占资源的进程,提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请
破坏循环等待条件
对系统所有资源类型进行线性排序,并赋予不同序号,规定每个进程必须按序号递增的顺序请求资源
避免死锁
把系统状态分为安全状态和不安全状态。
在系统进行资源分配前,先计算系统能否按照某种进程推进顺序分配资源,从而满足每个进程对资源的需求,若可以,则可找到安全序列,称系统处于安全状态
若找不到这样一个安全序列,则称系统处于不安全状态
银行家算法
这个算法是最有代表性的避免死锁算法,由Dijkstra提出。银行家算法要求每一个新进程进入系统时都必须申明运行时所需的各种资源的最大数目,且不能超过对应的系统拥有总量,同时要求系统维护四个数据结构:
- 一个m维向量Available,
Available[j]=K
表示系统中第j类资源的当前可用数目为K,显然该向量的初始值为系统全部资源的可用数目; - 一个n×m的矩阵Max,
Max[i][j]=K
表示进程i对第j类资源的最大需求数目为K; - 一个n×m的矩阵Allocation,
Allocation[i][j]=K
表示进程i当前已分得的第j类资源数目为K; - 一个n×m的矩阵Need,
Need[i][j]=K
表示进程i还需要第j类资源K个才能完成任务
显然Max[i][j]=Need[i][j]+Allocation[i][j]
有了这些数据结构,就可以进行安全性检查了。对于到来的进程Pi,设它对资源的请求向量为Requesti,Requesti[j]=KRequesti[j]=K表示该进程对第j类资源的需求量为K,接下来开始执行检查:
-
若
Requesti[j]≤Need[i][j]
,则进行下一步,否则认为出错,因为这代表它请求的资源数大于它所需要的资源数; -
若
Requesti[j]≤Available[j]
,则进行下一步,否则令进程等待,因为此时资源不足以保证进程的运行; -
系统修改数据结构的值(即模拟资源分配):
Available[j]=Available[j]−Request[i][j]
Allocation[i][j]=Allocation[i][j]+Requesti[j]
Need[i][j]=Need[i][j]−Requesti[j]
死锁的检测与解除
系统应当提供两个算法:
-
死锁检测算法。该方法用于检测系统状态,以确定系统中是否发生了死锁。
-
资源分配图,圆圈代表进程,方框代表一类资源,边代表请求/分配
-
死锁原理:当且仅当S状态的资源分配图是不可完全简化的,则S为死锁状态
化简方法:可以找出所有既不阻塞也非独立的进程结点,然后同时去掉与它相连的所有请求边和分配边(即使之孤立)。若所有的进程都可以顺利执行,那么图中的所有边都应被消去,即最终资源分配图是可以被完全简化的
-
-
死锁解除算法:当认定系统中已发生了死锁,利用该算法可将系统从死锁状态中解脱出来。
- 抢占资源,即掠夺其他进程的资源给死锁进程;
- 终止进程,即终止系统中若干个死锁进程以打破环路。