银行家算法是最具有代表性的避免死锁的算法。
1、算法原理
银行家算法:当一个新进程进入系统时,该进程必须申明在运行过程中所需要的每种资源的最大数目,且该数目不能超过系统拥有的资源总量。当进程请求某组资源时,系统必须先确定系统中是否有足够的该类资源供以分配给该进程。若有,通过安全性算法来计算,将资源分配给该进程后,是否会使系统处于不安全状态,如果不会处于安全状态,则将资源分配给该进程,否则让进程等待。若没有,进程等待。
2、数据结构
可利用资源向量 Available ,它是一个含有 m 个元素的数组,其中的每一个元素代表一类可利用的资源的数目,其初始值是系统中所配置的该类全部可用资源数目。其数值随该类资源的分配和回收而动态地改变。如果Available[j]=k,表是系统中现有 Rj 类资源 k 个。
最大需求矩阵 Max,这是一个 n×m 的矩阵,它定义了系统中 n 个进程中的每一个进程对 m 类资源的最大需求。如果Max[i,j]=k,表示进程 i 需要 Rj 类资源的最大数目为 k 。
分配矩阵 Allocation ,这是一个 n×m 的矩阵,它定义了系统中的每类资源当前一分配到每一个进程的资源数。如果Allocation[i,j]=k,表示进程 i 当前已经分到 Rj 类资源的数目为 k。Allocation[i] 表示进程 i 的分配向量,有矩阵 Allocation 的第 i 行构成。
需求矩阵 Need ,这是一个n×m的矩阵,用以表示每个进程还需要的各类资源的数目。如果Need[i,j]=k,表示进程 i 还需要 Rj 类资源 k 个,才能完成其任务。Need[i] 表示进程 i 的需求向量,由矩阵 Need 的第 i 行构成。
三个矩阵间存在关系:Need[i,j]=Max[i,j]-Allocation[i,j];
3、银行家算法
设 Request 是进程Pi的请求向量,如果 Requesti[j] = K,表示进程 Pi 需要 K 个 Rj 类型的资源。当 Pi 发出资源请求后,系统按下述步骤进行检査:
①如果 Requesti[j] ≤ Need[i,j]便转向步骤 2;否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
②如果 Requesti[j] ≤ Available[j],便转向步骤 3;否则,表示尚无足够资源,Pi须等待。
③系统试探着把资源分配给进程 Pi,并修改下面数据结构中的数值
Available[j] = Available[j] - Requesti[j]; // 分配出去
Allocation[i,j] = Allocation[i,j] + Requesti[j]; // 获得资源
Need[i,j] = Need[i,j] - Requesti[j]; // 需求减少
④系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程 Pi ,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程 Pi 等待。
4、安全性算法
①设置两个向量:① 工作向量 Work ,它表示系统可提供给进程继续运行所需的各类资源数目,它含有 m 个元素,在执行安全算法开始时,Work = Available;② Finish: 它表示系统是否有足够的资源分配给进程,使之运行完成。默认全部为 False。
②从进程集合中找到一个能满足下述条件的进程
Finish[i] = False;
Need[i] ≤ Work; (向量比较)
若找到,执行步骤 3,否则,执行步骤 4 ;
③当进程 Pi 获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:
Work = Work + Allocation[i] (向量运算)
Finish[i] = True;
转到步骤 2
④如果所有进程的 Finish[i] = True都满足,则表示系统处于安全状态;否则,系统处于不安全状态。
5、实现代码
1. 函数security(work, need, allocation):
- 该函数用于检查系统在给定资源情况下是否可以满足所有进程的需求并避免死锁。
- 参数包括当前可用资源work、每个进程还需要的资源need以及已分配给每个进程的资源allocation。
- 通过循环遍历进程,并找到可以完成的进程,直到所有进程都完成或无法分配资源为止。
2. 函数printTable(available, max_table, allocation, need):
- 该函数用于打印进程的最大需求矩阵、分配矩阵以及还需要的资源矩阵。
- 参数包括当前剩余资源available、每个进程的最大需求矩阵max_table、分配矩阵allocation和还需要的资源矩阵need。
3. 主函数main():
- 要求用户输入资源种类数量m和各类资源的数量available。
- 用户输入进程数量n,以及每个进程的最大需求矩阵和分配矩阵。
- 计算每个进程还需要的资源矩阵need,以及当前剩余资源available。
- 循环进行用户输入请求的过程,用户可以输入请求的进程索引和需求数组。
- 根据用户输入的请求,判断请求是否合法,并根据安全性算法进行分配判断。如果分配后系统处于安全状态,则重新输出进程信息;否则提示不安全,撤销分配操作。
- 主函数通过调用security()函数来检查安全性,然后打印当前进程的资源分配情况。
4. Numpy
由于机器学习算法在数据处理过程中大都涉及线性代数的知识,需要用到矩阵操作,Python本身没有处理矩阵的数据类型,因此需要使用附加的函数库numpy
import numpy as np
def printt(available, max_table, allocation, need):
print("进程\tMax\tAllocation\tNeed")
for i in range(5):
print("P{}\t{}\t{}\t{}".format(i, max_table[i], allocation[i], need[i]))
print("当前剩余资源:", available)
def anquan(work, need, allocation):
n = need.shape[0]
finish = np.array([False] * n, dtype=bool)
while not (finish.all()):
flag = False
for i in range(n):
if not finish[i] and (need[i] <= work).all():
print("安全序列P{}".format(i), end=',')
flag = True
work += allocation[i]
finish[i] = True
break
if not flag: return False
print()
return True
def main():
m = int(input("资源种类: "))
tt = input("各类资源的数量:").split()
available = np.array(tt, dtype=int)
n = int(input("进程数量: "))
max = np.zeros([n, m], dtype=int)
allocation = np.zeros([n, m], dtype=int)
for i in range(n):
tt = input("进程 P{} 的最大需求矩阵向量:".format(i)).split()
max[i] = np.array(tt, dtype=int)
if (available < max[i]).any():
print("输入错误")
i -= 1
for i in range(n):
tt = input("进程 P{} 的分配矩阵向量:".format(i)).split()
allocation[i] = np.array(tt, dtype=int)
if (max[i] < allocation[i]).any():
print("输入错误")
i -= 1
need = max - allocation
for i in allocation:
available -= i #剩余资源
printt(available, max, allocation, need)
while (need != 0).any():
pid, qq= input("输入请求: ").split(',')
pid = int(pid[1:])
qq = np.array(qq.split(), dtype=int)
if (qq > max[pid]).any():
print("输入错误")
else:
available -= qq
allocation[pid] += qq
need[pid] -= qq
if anquan(available.copy(), need, allocation):
printt(available, max, allocation, need)
continue
else:
print("不安全 不可分配")
available += qq
allocation[pid] -= qq
need[pid] += qq
if __name__ == '__main__':
main()
6、运算结果