思路
1)银行家算法的数据结构
2)银行家算法的数学描述
就是先简单检查一下请求的数量够不够分。然后(4)安全性算法就是检验有没有 安全序列,就是未来够不够发。
- 检查Request > Need吗?大于就不能分配。Need是最多还能要多少资源就完成任务了。进程A一共才需要三个苹果,单次申请是否超过三个苹果。
- 检查Request > Available吗?大于就不能分配。Available是现在还剩多少。OS还剩两个苹果,单次申请不能超过两个。
- 分配资源,更新数据结构or三个矩阵。
- 调用安全性检查算法,看看有没有安全序列。若没有安全序列,步骤三的分配作废并恢复。
3)安全性算法的数学描述
检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。
不断重复上述过程,看最终是否能让所有进程都加入安全序列。
代码
import random
import threading
import time
from typing import Optional, Callable, Any, Iterable, Mapping
import numpy as np
import pandas as pd
class myThread(threading.Thread):
# 注解表示函数的返回类型,用标识符-> 。它是可选的,如果删掉,什么都不会影响。
'''我试着寻找这两者的区别和各自优势。有以下发现:
1. 将动态类型函数改为静态类型函数并不能使计算加快;
2. 就算你静态限定了int,输入为float的时候也不会报错,输出也不会变成期待的int类型。所以在使用上,动静态类型并没有区别。'''
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None) -> None:
super().__init__(group, target, name, args, kwargs, daemon=daemon)
"""
初始化参数
:param Max: 最大需求矩阵
:param Allocation: 已经分配矩阵
:param Need: 需求矩阵
:param PID: 进程PID
"""
self.Max = random.randint(1, 10)
self.Allocation = 0
self.Need = self.Max - self.Allocation
s =str(random.randint(0, 999))
self.PID = s.zfill(3)
def run(self) -> None:
super().run()
print(f"-----进程{self.PID}运行中-----")
while self.Allocation != self.Max :
time.sleep(random.randint(1, 2))
self.request()
time.sleep(random.randint(4, 8))
def __str__(self) -> str:
return super().__str__()
# 发出新的请求
def request(self):
req = random.randint(1, int(self.Need * 1.5))
if BankerAlgorithm(self.PID, req):
# 如果可以分配这个请求就分配
print(f"银行家给进程{self.PID}分配资源{req}")
self.Allocation += req
self.Need = self.Max - self.Allocation
else:
# 如果分配不了,就说一声
print(f"银行家不给进程{self.PID}分配资源{req}")
def BankerAlgorithm(PID, Req) -> bool:
global myThreadList, Available
Lock.acquire()
print(f"进程{PID}申请{Req}个资源")
# 先进行三次判断
"""
初始化参数
:param Max: 最大需求矩阵
:param Allocation: 已经分配矩阵
:param Need: 需求矩阵
:param PID: 进程ID
"""
MaxList = {T.PID: T.Max for T in myThreadList}
AllocationList = {T.PID: T.Allocation for T in myThreadList}
NeedList = {T.PID: T.Need for T in myThreadList}
IDList = {T.PID: T.PID for T in myThreadList}
data = {**{"PID": IDList}, **{"Max": MaxList}, **{"Allocation": AllocationList}, **{"Need": NeedList},
**{"Available": Available}}
df = pd.DataFrame(data)
print("----银行家算法前-----")
print(df)
# 1. 判断是否大于Need
if Req > NeedList.get(PID):
print(f"进程{PID}申请的资源数目{Req}大于该进程最大所需量Need={NeedList.get(PID)}")
Lock.release()
return False
# 2. 判断是否大于Available
if Req > Available:
print(f"进程{PID}申请的资源数目{Req}大于OS拥有的资源数{Available}")
Lock.release()
return False
# 3. 尝试分配,然后Available- Need- Allocation+
AllocationList.update({PID: AllocationList.get(PID) + Req})
NeedList.update({PID: NeedList.get(PID) - Req})
Available -= Req
data = {**{"PID": IDList}, **{"Max": MaxList}, **{"Allocation": AllocationList}, **{"Need": NeedList},
**{"Available": Available}}
df = pd.DataFrame(data)
print("-----尝试分配,然后进行安全性检验-----")
print(df)
# 4. 进行安全性检验
if not SecurityAlgorithm(NeedList, Available,AllocationList):
print(f"进程{PID}不存在安全序列,拒绝分配资源")
# 还原刚才尝试分配的
Available += Req
Lock.release()
return False
Lock.release()
return True
def SecurityAlgorithm(NeedList, Available,AllocationList) -> bool: # 存在安全序列返回True
# 安全序列
SafeList = []
keyList = list(NeedList.keys())
Flag = 1
while len(keyList)!=0 and Flag==1:
Flag = 0
for key in keyList:
if Available >= NeedList.get(key):
# 如果拥有的多
SafeList.append(key)
keyList.remove(key)
Available += AllocationList.get(key)
# 表示能找到
Flag = 1
if len(keyList)==0:
# 找到了
print("找到安全序列为",SafeList)
return True
print("找不到安全序列")
return False
if __name__ == '__main__':
# self.Max = random.randint(1, 10)
Num = 4
Available = random.randint(Num * 4, Num * 8)
Lock = threading.Semaphore(value=1)
myThreadList = [myThread() for i in range(Num)]
# 轮流启动
for T in myThreadList:
T.start()
结果展示
下面我们来分析一下实验的正确性,如下图1。首先,进程769申请5个资源,然后银行家判断是否大于Need,Allocation。因为5<6,5<7。然后分配之后Available还剩2个资源。安全序列,对于进程386,2=2所以Available增加为8。对于进程859,8>7,所以Available增加为8。对于进程769,8>1所以Available增加为13。最后对于进程793,13>10,所以Available增加为13。因此可以找到安全序列386->859->769->793。因此四项考验都通过了,可以给769分配。
- 1“成功分配”结果
接着分析不成功的情况,如下图2。申请3个资源,但是此时OS里面只有2个资源。3<2因此,不能分配。也不用判断安全序列。
- 2 “申请资源大于拥有资源”结果分析
分析另一个分配失败的情况如下图3,进程894申请10个资源,但是进程就需要8个资源。因此不能给进程分配。
- 3 “申请资源大于最大需要资源”结果
下面我们来分析最后一种失败原因,如下图4。首先,进程825申请2个资源,然后银行家判断是否大于Need,Allocation。因为2<9,2<5。然后分配之后Available还剩3个资源。安全序列,对于进程227,3=3所以Available增加为3。然后判断,发现3<10,7,10因此找不到一个安全序列。不能分配资源。
4“没有安全序列”结果