Python 实现OS银行家算法

思路

1)银行家算法的数据结构

2)银行家算法的数学描述

就是先简单检查一下请求的数量够不够分。然后(4)安全性算法就是检验有没有 安全序列,就是未来够不够发。
  1. 检查Request > Need吗?大于就不能分配。Need是最多还能要多少资源就完成任务了。进程A一共才需要三个苹果,单次申请是否超过三个苹果。
  2. 检查Request > Available吗?大于就不能分配。Available是现在还剩多少。OS还剩两个苹果,单次申请不能超过两个。
  3. 分配资源,更新数据结构or三个矩阵。
  4. 调用安全性检查算法,看看有没有安全序列。若没有安全序列,步骤三的分配作废并恢复。

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“没有安全序列”结果

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值