银行家算法

银行家算法

银行家算法在OS中可以避免死锁。

实现 银行家算法需要四个数据结构用来分别描述:系统中可利用的资源,所有进程对资源的最大需求,系统中资源的分配情况,所有进程还需要多少资源。

  1. 一维数组Available(可利用资源):每个资源代表一类资源的数目。其中的值会随着资源的Allocation分配和回收动态改变。
  2. 矩阵Max(最大需求):n*m矩阵,表示n个进程对m类资源的最大需求。
  3. 矩阵Allocation(当前分配资源):n*m矩阵,表示系统对n个进程关于m类资源的已分配数目。
  4. 矩阵Need(进程尚需资源):n*m矩阵,表示n个进程对m类资源尚需的数目;其中有关系Need[i,j]=Max[i,j]-Allocation[i,j]。

另外一个变量n*m二维数组Request表示n个进程当前向系统请求的m类资源的数量

当一个进程pi向系统请求资源,Requesti[j]=k,表示对第j类资源请求k个资源,系统按一下步骤进行:

  1. 如果Requesti[j]<=Needi[j],说明请求资源不超过声明的尚需最大资源,是合法的,可以进入下一步;否则不合法,因为请求资源超过声明的尚需最大请求量。
  2. 如果Requesti[j]<=Available[j],则表示当前系统空闲的第j类资源Available[j]可以满足进程pi请求的资源,允许进入下一步;否则当前进程pi需要等待。(可用for循环按顺序查找,遍历一边 )
  3. 当系统尝试满足pi的请求,会有以下的操作
    1. Available[j]=Available[j]-Requesti[j],因为资源分配出去,相应的资源就会减少。
    2. Need[i,j]=Need[i,j]-Requesti[j],更新尚需资源数
    3. Allocation[i,j]=Allocation[i,j]+Requesti[j],更新已分配资源情况。
  4. 执行玩第三步,还需要进行安全性检查,若安全则允许分配,否则第三步作废,数据恢复到第三步操作前的状态。(对应多个安全序列)

安全性算法如下:

  1. 设置两个变量,第一个是一个一维数组Work,表示系统可分配给进程的各类资源数目,开始运行安全算法时,Work=Available:第二个是一个一维bool类型数组Finish,表示集合中各个进程是否完成,开始时全部设置为FALSE。若系统有足够资源分给Pi时,再设置Finish[i]=TRUE。
  2. 从进程集合种寻找能满足下面条件的进程pi: Finish[i]=FALSE(即尚未完成),Need[i,j]<=Work[j](尚需资源可被当前系统满足的)。若找得到就进入第三步,否则进入第四步。
  3. 执行以下操作:
    1. Work[j]=Work[j]+Allocation[i,j],即若执行完Pi后,要释放相应的资源。
    2. Finish[i]=TRUE,标记该进程执行完毕
    3. 回到第二步继续执行(while循环的条件是第二步中的两个条件)
  4. 查找全部Finish,若全为TRUE则表示该系统处于安全状态,有一个对应的安全序列(不唯一) 。否则不安全。

实现代码如下:

/*
 * @Author: pumpkins
 * @Date: 2021-10-23 14:50:27
 * @LastEditTime: 2021-10-24 01:09:32
 * @FilePath: \Vscode_workspace\OS\银行家算法.cpp
 */
#pragma warning(disable : 4996)
#include <cstdio>
#define proNum 5                                                                          //进程数目
#define resNum 3                                                                          //资源种类
int Available[resNum] = {3, 3, 2};                                                        //系统当前的各类资源可用数目
int Need[proNum][resNum] = {0};                                                           //当前各个进程对各类资源尚需的数目
int Max[proNum][resNum] = {{7, 5, 3}, {3, 2, 2}, {9, 0, 2}, {2, 2, 2}, {4, 3, 3}};        //各个进程对各类资源的最大需求数目
int Allocation[proNum][resNum] = {{0, 1, 0}, {2, 0, 0}, {3, 0, 2}, {2, 1, 1}, {0, 0, 2}}; //当前系统给各个进程已经分配的各类资源的情况
int n = 1;                                                                                //请求执行的进程号
int Request[resNum];                                                                      //请求资源序列
void print();
void bank();
bool safeTest();
int main(void)
{
    for (int i = 0; i < proNum; ++i) //初始化Need
    {
        for (int j = 0; j < resNum; ++j)
        {
            Need[i][j] = Max[i][j] - Allocation[i][j];
        }
    }
    while (n + 1) //输入要执行的进程序号,输入负数退出
    {
        bool flag = true;                //标记所有进程是否都已执行完毕,先假设都完成
        for (int i = 0; i < proNum; ++i) //如果Need全为0说明执行完毕
        {
            if (flag == false)
                break;
            for (int j = 0; j < resNum; ++j)
            {
                if (Need[i][j] != 0)
                {
                    flag = false;
                    break;
                }
                flag = true;
            }
        }
        if (flag == true)
        {
            printf("所有进程已执行完毕!\n");
            break;
        }

        print(); //输出当前资源分配情况
        printf("请输入要请求的进程序号:");
        scanf("%d", &n);
        if (n < 0)
            break;
        printf("请输入资源的请求向量:");
        for (int i = 0; i < resNum; ++i)
        {
            scanf("%d", &Request[i]);
        }
        bank(); //银行家算法
    }
    printf("结束!\n");
}
void print() //用于输出当前进程和资源分配状态
{
    printf("    Max       Allocation  Need\n");
    printf("    A  B  C   A  B  C     A  B  C\n");
    for (int i = 0; i < proNum; ++i)
    {
        printf("p%-3d", i);
        printf("%-3d%-3d%-4d", Max[i][0], Max[i][1], Max[i][2]);
        printf("%-3d%-3d%-6d", Allocation[i][0], Allocation[i][1], Allocation[i][2]);
        printf("%-3d%-3d%-4d", Need[i][0], Need[i][1], Need[i][2]);
        printf("\n");
    }
    printf("Available: A:%3d B:%3d C:%3d", Available[0], Available[1], Available[2]);
    printf("\n");
}
void bank() //银行家算法
{
    //第一步,先判断是否满足Request~i~[j]<=Need
    for (int i = 0; i < resNum; ++i)
    {
        if (Request[i] > Need[n][i]) //如果请求的资源大于最大需求量,说明请求不合法
        {
            printf("请求不合法!请求的资源数量不可大于最大需求量!\n");
            return;
        }
    }
    //第二步,判断是否满足Request~i~[j]<=Available[j]
    for (int i = 0; i < resNum; ++i)
    {
        if (Request[i] > Available[i]) //如果请求的资源数目大于当前系统的空闲资源数,则需要等待
        {
            printf("当前系统资源不足,p%d需要等待。\n");
        }
    }
    //第三步进行安全性测试决定是否分配资源
    if (safeTest() == true)
    {
        printf("分配后系统处于安全状态,系统可满足p%d的资源请求!\n", n);
    }
    else
    {
        printf("分配后系统处于不安全状态,因此无法满足p%d的资源请求!\n", n);
    }
    printf("\n");
}
bool safeTest() //安全性测试
{
    //更新为分配后的状态,并暂时记录分配前的状态,若分配后不安全就恢复
    int tmpAva[resNum];
    int tmpNeed[proNum][resNum];
    int tmpAllo[proNum][resNum];
    for (int j = 0; j < resNum; ++j)
    {
        tmpAva[j] = Available[j];

        Available[j] -= Request[j];
        for (int i = 0; i < proNum; ++i)
        {
            tmpNeed[i][j] = Need[i][j];
            tmpAllo[i][j] = Allocation[i][j];

            //进程Pn的状态信息需要改变
            if (i == n)
            {
                Need[i][j] -= Request[j];
                Allocation[i][j] += Request[j];
            }
        }
    }

    //进行安全测试
    int quen[proNum], tmp = 0; //记录安全序列
    int Work[resNum];
    bool Finish[proNum] = {false};   //标记进程是否完成,开始时全为false
    for (int i = 0; i < resNum; ++i) //初始时Work为Available
    {
        Work[i] = Available[i];
    }

    bool flag = true;
    while (flag)
    {
        flag = false; //标记是否找到一个可执行进程
        for (int i = 0; i < proNum; ++i)
        {
            if (Finish[i] == false) //先要满足未执行完毕
            {
                flag = true;
                for (int j = 0; j < resNum; ++j) //需要满足所有类资源才可继续执行
                {

                    if (Need[i][j] > Work[j]) //不满足条件
                    {
                        flag = false;
                        break;
                    }
                }
                if (flag == true) //找到了满足条件的可以执行的进程
                {
                    for (int j = 0; j < resNum; ++j)
                    {
                        Work[j] += Allocation[i][j]; //释放资源
                    }
                    Finish[i] = true; //标记该进程完成
                    quen[tmp] = i;    //计入安全序列
                    tmp++;
                    //break;                  //这里不break也可以,只是不同的思路,break是找到一个后又重头找;不break是找到后继续向后找
                }
            }
        }
    }

    for (int i = 0; i < proNum; ++i) //若有进程无法完成,则不安全
    {
        if (Finish[i] == false)
        {
            //恢复
            for (int j = 0; j < resNum; ++j)
            {
                Available[j] = tmpAva[j];
                for (int i = 0; i < proNum; ++i)
                {
                    Need[i][j] = tmpNeed[i][j];
                    Allocation[i][j] = tmpAllo[i][j];
                }
            }
            return false;
        }
    }
    //安全。输出安全序列,并且释放资源
    for (int i = 0; i < resNum; ++i)
    {
        Available[i] += Allocation[n][i];
    }
    printf("该情况下的一个安全序列为:");
    for (int i = 0; i < proNum; ++i)
    {
        printf("p%d ", quen[i]);
    }
    printf("\n");
    return true;
}

其中安全序列并不唯一,上面有两种思路,见172行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值