实验二 银行家算法
一、实验目的
1、了解什么是操作系统安全状态和不安全状态;
2、了解如何避免系统死锁;
3、理解银行家算法是一种最有代表性的避免死锁的算法,掌握其实现原理及实现过程。
二、实验内容
根据银行家算法的基本思想,编写和调试一个实现动态资源分配的模拟程序,并能够有效避免死锁的发生。
三、实验原理
进程申请资源时,系统通过一定的算法判断本次申请是否不可能产生死锁(处于安全状态)。若可能产生死锁(处于不安全状态),则暂不进行本次资源分配,以避免死锁。算法有著名的银行家算法。
1、什么是系统的安全状态和不安全状态?
所谓安全状态,是指如果系统中存在某种进程序列<P1,P2,…,Pn>,系统按该序列为每个进程分配其所需要的资源,直至最大需求,则最终能使每个进程都可顺利完成,称该进程序列<P1,P2,…,Pn,>为安全序列。
如果不存在这样的安全序列,则称系统处于不安全状态。
2、银行家算法
把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金。
操作系统按照银行家制定的规则设计的银行家算法为:
(1)进程首次申请资源的分配:如果系统现存资源可以满足该进程的最大需求量,则按当前的申请量分配资源,否则推迟分配。
(2)进程在执行中继续申请资源的分配:若该进程已占用的资源与本次申请的资源之和不超过对资源的最大需求量,且现存资源能满足该进程尚需的最大资源量,则按当前申请量分配资源,否则推迟分配。
(3)至少一个进程能完成:在任何时刻保证至少有一个进程能得到所需的全部资源而执行到结束。
银行家算法通过动态地检测系统中资源分配情况和进程对资源的需求情况来决定如何分配资源,并能在确保系统处于安全状态时才把资源分配给申请者,从而避免系统发生死锁。
四、实验中用到的系统调用函数(包括实验原理中介绍的和自己采用的),自己采用的系统调用函数要按照指导书中的格式说明进行介绍。
模拟程序没有用到系统调用函数
五、实验步骤
要求写出实验过程和思路。
流程图:
银行家算法数据结构:
1、系统可利用资源向量Available[m]
这是一个含有m个元素的数组,其中每一个元素代表一类系统可利用资源数目,其初始值随机生成,其数值随该类资源的分配和回收而动态的改变。Available[i]=N表示系统中现有第i类资源N个。
2、最大需求矩阵Max
这是一个含有n*m大小的矩阵,其定义了每个进程对系统某类资源的最大需求量。Max[i][j]=N表示进程i对第j类资源的需求为N个。
3、进程已拥有资源矩阵Allocation
这是一个含有n*m大小的矩阵,其定义了每个进程对系统某类资源的已拥有个数。Allocation[i][j]=N表示进程i对第j类资源的已拥有数为N。
4、进程需求矩阵Need
这是一个含有n*m大小的矩阵,其定义了每个进程对系统某类资源的需求数量,Need[i][j]=N表示进程i对第j类资源的需求为N。
其中,Need、Allocation、Max矩阵的关系为:Need[i][j]=Max[i][j]-Allcation[i][j]
以上数组全部由C++对内存空间申请动态数组实现。
5、进程请求向量request
这是一个含有m个元素的数组,其中每一个元素代表此时某进程对每一类系统可利用资源的申请数量,数值大小不超过系统可利用的资源数。request[i]=N表示某进程对第i类资源的申请数为N。
6、Temp
这是一个含有m个元素的数组,其初始值为Available,将对Available的操作代替在Temp上进行。
7、进程满足需求的标志数组Finish
在安全性检测中对每个进程进行检测分配时,可满足的进程即标志位置1。
Finish[i]=1表示此次尝试分配资源后系统可利用资源能满足第i个进程的需求。
银行家算法思路:
申请资源RequestRes():
1、产生申请向量
2、与系统可利用资源对比(request[i]<=Available[i])判断能否满足,能则转步骤3,否则直接返回。
3、足够资源分配,尝试分配资源
4、执行安全性检测算法
5、如安全性检测不通过,回收分配出去的资源
安全性检测算法思路:
1、初始化Temp与Finish,使Temp[i]=Available[i],Finish[i]=0
2、当Finish[i]=0&&Need<=Temp时转步骤3,否则转步骤4
3、进程获得所需资源,视为执行完毕,释放所有资源,使Temp=Temp+Available
Finish[i]=1。
4、计数Finish数组是否全为1,是则系统安全,可以分配,否则不安全。
六、实验结果分析(截屏的实验结果,与实验结果对应的实验分析)
在程序设计方面,我已经事先对初始化的数据进行安全性检验,确保初始化的数据不会产生死锁,是能够通过安全性检验的具有安全序列的数据。
将系统此时可利用资源分配给P1,满足全部需求,默认执行完毕回收P1的资源。此时系统可利用资源为6 4 13 14 6 8 2。满足P0全部需求。故安全性检测通过。可以分配资源。本次随机产生的系统拥有资源较多,但第二类资源从P1中收回后为4个刚好满足P0总需求,要是少一个则会发生死锁。
将此时系统可利用资源分配给P0,满足其全部需求后回收P0拥有的资源,此时系统可利用资源为9 5 12 10 9 8 7 9 12。满足P1的全部需求,将所需资源全分配给P1后回收P1的资源,此时系统可利用资源为10 6 14 12 10 11 8 12 16满足P2全部需求,故安全性检测通过,可以分配。
检测系统可利用资源不足以分配申请资源,直接返回。
初始时系统剩余可利用资源为2 6 3 4 7,满足安全性,安全序列为1→2→3→0(不唯一),当尝试分配后剩余1 5 1 2 6,无法满足任一进程需求,安全性检测不通过。如分配则造成系统死锁,故分配失败。
系统尝试分配后剩余可利用资源8 0 2 1 8 0 4 2
此时执行安全检测,对于进程0,满足需求,全部分配后收回资源。
此时系统可利用资源为9 1 3 3 13 1 8 6
按顺序到进程1,对比Need,发现第三类资源不足,跳过
按顺序到进程2,对比Need,发现第二类资源不足,跳过
按顺序到进程3,对比Need,满足需求,全部分配后收回资源。
此时系统可利用资源为11 2 4 7 14 3 9 9
按顺序到进程4,对比Need,发现第二类资源不足,跳过
按顺序到进程5,对比Need,发现第二类资源不足,跳过
再次循环,对进程1,对比Need,发现第六类资源不足,跳过
循环完毕,发现满足进程不足全部,撤销分配的资源,返回不安全。
初始系统可利用资源的产生为[1,9]之间,最大需求资源的产生范围为[0.9],已分配资源产生范围为[0,5],申请资源产生范围为[0,还需求数]。通过研究发现,改变系统可利用资源的产生范围为[1,5]之间,实验结果有80%为系统无足够资源分配,直接结束程序。这是因为要能分配必须保证系统每一类可利用资源都满足申请资源数,但系统可利用资源较少,随机产生的申请资源数较高,且一旦系统资源种类有很多时要保证每一类都满足是比较困难的。可以通过调高系统可利用资源的产生范围或者调低随机产生的系统资源种类数来提高申请通过率。
关于算法效率方面,在安全性检测中用到了嵌套三层for循环来对每个进程进行尝试分配检测,时间复杂度为O(n3),由于银行家算法的原理,每次尝试分配资源之后必须对当前所有进程进行安全性检测,找到一个安全序列之后才能成功分配,所以对每个进程的检测是必不可少的,目前还没有想到比较明显的能够实现该目的且效率较高的算法。
七、思考题
1、 如何设计程序的输入模块才能满足实验要求,请举例说明;
由实验要求可知,测试数据全部不可手工输入。现在设定所有数据全部随机生成。初始数据中,在[1,10]随机生成资源类数和进程数,对Available数组、Max数组随机生成数据并赋值,对Allocation数组的数据随机生成中,要求生成的数据不可大于Max数组中对应数据,大于则重新生成。Need数组中数据要求为Max数组的值-已分配Allocation数组中对应的值。嵌套循环里进行相减赋值即可。设计申请资源向量request时,随机产生的需求数一定要小于或等于需求数,在这里我写的产生范围为[0,还需求数]。
2、 银行家算法在实现过程中必须注意哪些资源分配细节才能避免死锁?
(1)对比请求资源向量和系统当前可利用资源向量,如果某一类资源不满足请求则直接返回分配资源失败。
(2)系统可利用资源满足需求时,试探性分配更新数据中,应使系统可利用资源Available=Available-request,已拥有资源Allocation=Allocation+request,需求向量Need=Need-request。
(3)初始化系统资源时应进行安全性检测,如果初始化时产生的数据都无法使进程拥有安全序列,后面的银行家算法执行将没有任何意义。
八、实验数据及源代码(学生必须提交自己设计的程序源代码,并有注释,源代码电子版也一并提交),包括思考题的程序。
程序完整代码请转至个人GitHub仓库(如果喜欢,麻烦点个star✨谢谢~)
结语:随笔仅供参考,千万不要照抄哦~我相信你可以的~!