zoukankan      html  css  js  c++  java
  • 银行家算法学习笔记

    https://www.cnblogs.com/chuxiuhong/p/6103928.html


    死锁避免——银行家算法的应用背景

      1、要想说银行家,首先得说死锁问题,因为银行家算法就是为了死锁避免提出的。那么,什么是死锁?简单的举个例子:俩人吃饺子,一个人手里拿着酱油,一个人手里拿着醋,拿酱油的对拿着醋的人说:“你把醋给我,我就把酱油给你”;拿醋的对拿着酱油的人说:“不,你把酱油给我,我把醋给你。”

      于是,俩人这两份调料是永远吃不上了。这就是死锁。

      2、那么,为啥这个算法叫银行家算法?因为这个算法同样可以用于银行的贷款业务。让我们考虑下面的情况。

    • 一个银行家共有20亿财产
    • 第一个开发商:已贷款15亿,资金紧张还需3亿。
    • 第二个开发商:已贷款5亿,运转良好能收回。
    • 第三个开发商:欲贷款18亿

      在这种情况下,如果你是银行家,你怎么处理这种情况?一个常规的想法就是先等着第二个开发商把钱收回来,然后手里有了5个亿,再把3个亿贷款给第一个开发商,等第一个开发商收回来18个亿,然后再把钱贷款给第三个开发商。或者呢,先借给第一个开发商3亿,等他还了钱给第三个开发商,此时第二个开发商没啥需求。
      这里面什么值得学习呢?最重要的就是眼光放长一点,不要只看着手里有多少钱,同时要注意到别人欠自己的钱怎么能收回来

      那么正经点说这个问题,第一个例子中:醋和酱油是资源,这俩吃饺子的是进程;第二个例子中:银行家是资源,开发商是进程。在操作系统中,有内存,硬盘等等资源被众多进程渴求着,那么这些资源怎么分配给他们才能避免“银行家破产”的风险?


    银行家算法

    安全序列:安全序列是指对当前申请资源的进程排出一个序列,保证按照这个序列分配资源完成进程,不会发生“酱油和醋”的尴尬问题。所以我们需要对请求进程排出个分配的序列!

    我们假设有进程P1,P2,.....Pn。则安全序列要求满足:Pi(1<=i<=n)需要资源<=剩余资源 + 分配给Pj(1 <= j < i)资源。为什么等号右边还有已经被分配出去的资源?想想银行家那个问题,分配出去的资源就好比第二个开发商,人家能还回来钱,咱得把这个考虑在内。

    我们定义下面的数据结构(想想那个银行家的例子)

    int n,m; //系统中进程总数n和资源种类总数m
    int Available[1..m]; //资源当前可用总量
    int Allocation[1..n,1..m]; //当前给分配给每个进程的各种资源数量
    int Need[1..n,1..m];//当前每个进程还需分配的各种资源数量
    int Work[1..m]; //当前可分配的资源
    bool Finish[1..n]; //进程是否结束

    安全判定算法

    1.初始化

    Work = Available(动态记录当前剩余资源)
    Finish[i] = false(设定所有进程均未完成)

    2.查找可执行进程Pi(未完成但目前剩余资源可满足其需要,这样的进程是能够完成的)

    Finish[i] = false          
    Need[i] <= Work 
    如果没有这样的进程Pi,则跳转到第4步

    3.(若有则)Pi一定能完成,并归还其占用的资源,即:

    Finish[i] = true           
    Work = Work +Allocation[i]
    GOTO 第2步,继续查找

    4.如果所有进程Pi都是能完成的,即Finish[i]=ture
    则系统处于安全状态,否则系统处于不安全状态

    伪代码:

    Boolean Found;
    Work = Available; Finish[1..n] = false; 
    while(true){
        //不断的找可执行进程
       Found = false;
       for(i=1; i<=n; i++){
         if(Finish[i]==false && Need[i]<=Work){
            Work = Work + Allocation[i];//把放出去的贷款也当做自己的资产
            Finish[i] = true; 
            Found = true;
          }
        }
       if(Found==false)break;
     }
    for(i=1;i<=n;i++) 
      if(Finish[i]==false)return “deadlock”; //如果有进程是完不成的,那么就是有死锁

    示例

    举个实际例子,假设下面的初始状态:

    processAllocationNeedAvailable
      A B C A B C A B C
    P0 0 1 0 7 4 3 3 3 2
    P1 2 0 0 1 2 2  
    P2 3 0 2 6 0 0  
    P3 2 1 1 0 1 1  
    P4 0 0 2 4 3 1  

    首先,进入算法第一步,初始化。
    那么Work = Available = [3 3 2]

    1、首先看P0:P0的Need为[7 4 3],Available不能满足,于是跳过去

    2、P1的Need为[1 2 2]可以满足,我们令Work = Allocation[P1] + Work,此时Work = [5 3 2]

    3、再看P2,P2的Need为[6 0 0],那么现有资源不满足。跳过去。

    4、看P3,那么看P3,Work可以满足。那么令Work = Allocation[P3] + Work,此时Work = [7 4 3]

    5、再看P4,Work可以满足。令Work = Allocation[P4] + Work ,此时Work = [7 4 5]。

    到此第一轮循环完毕,由于找到了可用进程,那么进入第二轮循环。

    6、看P0,Work此时可以满足。令Work = Allocation[P0] + Work ,此时Work = [7 5 5]

    7、再看P2,此时Work可以满足P2。令Work = Allocation[P2] + Work , 此时Work = [10 5 7]

    至此,算法运行完毕。找到安全序列<p1,p3,p4,p0,p2>,证明此时没有死锁危险。(安全序列未必唯一)。(仅是安全的序列)


    资源请求算法

    之前说完了怎么判定当前情况是否安全,下面就是说当有进程新申请资源的时候如何处理。
    我们将第i个进程请求的资源数记为Requests[i](此进程是原来就知道的进程,是在安全序列里面的。若新加入一个进程,需要重新计算安全序列)

    算法流程:

    1.如果Requests[i]<=Need[i],则转到第二步。否则,返回异常。这一步是控制进程申请的资源不得大于需要的资源

    2.如果Requests[i]<=Available,则转到第三步,否则Pi等待资源。

    3.如果满足前两步,那么做如下操作:

    Available = Available -Requests[i]
    Allocation = Allocation[i]+Requests[i]
    Need[i]=Need[i]-Requests[i]
    调用安全判定算法,检查是否安全。
    if(安全)
    {
        申请成功,资源分配
    }
    else
    {
        申请失败,资源撤回。第三步前几个操作进行逆操作
    }

    缺点:很少有进程在运行前就知道其申请资源大小,而且进程数目不一定固定。所以这个比较适合那种变化不大的应用场景,局限性比较大。

  • 相关阅读:
    sweep line 扫描线模型
    双指针&整数二分思路总结
    ELF文件格式
    flask-migrate数据库迁移出现sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (2059, <NULL>)
    腾讯面试题
    zabbix 调用飞书发送消息
    NFS服务部署
    Linux系统启动
    电商系统nuxt的布局目录代码分享
    电商系统中进行流量控制
  • 原文地址:https://www.cnblogs.com/huangfuyuan/p/9193900.html
Copyright © 2011-2022 走看看