银行家算法( 详解 )


一、什么是银行家算法?

银行家算法是操作系统的经典算法之一,用于避免死锁情况的出现。

它最初是为银行设计的(因此得名),通过判断借贷是否安全,然后决定借不借。

在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。
用在操作系统中,银行家、出借资金、客户,就分别对应操作系统、资源、申请资源的进程。

每一个新进程进入系统时,必须声明需要每种资源的最大数目,其数目不能超过系统所拥有的的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程,若有,再进一步计算在将这些资源分配给进程后,是否会使系统处于不安全状态如果不会才将资源分配给它,否则让进程等待。

二、银行家算法中的数据结构

为了实现银行家算法,在系统中必须设置这样四个数据结构:

1)Available向量:系统中可利用的资源数目

2)Max矩阵:每个进程对每种资源的最大需求

3)Allocation矩阵:每个进程已分配的各类资源的数目

4)Need矩阵:每个进程还需要的各类资源数

其中三个矩阵间存在下述关系:

Need[i,j] = Max[i,j] - allocation[i, j]

算法逻辑:
设Requesti是进程Pi的请求向量,如果Requesti[j]=K,表示进程Pi需要K个Rj类型的资源。当Pi发出资源请求后,系统按下述步骤进行检查:

(1) 若 Requesti[j] ≤ Need[i,j],转向(2),否则认为出错(因为它所需的资源数目已超过它所宣布的最大值)。

(2) 若 Requesti[j] ≤ Available[j],转向(3),否则须等待(表现为进程Pi受阻)。

(3) 系统尝试把资源分配给进程Pi,并修改下面数据结构中的数值:
Available[j] = Available[j] – Requesti[j]
Allocation[i,j] = Allocation[i,j] + Requesti[j]
Need[i,j] = Need[i,j] –Requesti[j]

(4) 试分配后,执行安全性算法,检查此次分配后系统是否处于安全状态。若安全,才正式分配;否则,此次试分配作废,进程Pi等待。

三、流程图

在这里插入图片描述

四、代码实现

#include<stdio.h>
#include<string.h>
#define PN 5//进程数
#define RN 4//资源种类数

typedef struct//定义结构体类型pcb
{
    char name[3];//进程名,如p0
    int max[RN];//最大资源值
    int allocation[RN];//已分配资源数
    int need[RN];//任需求资源数
}pcb;

struct//定义为结构体类型,方便赋值
{
    int flag[PN];//进程检测标志,1时表示已通过
    int safes[PN];//存放进程编号,作为安全序列输出
}fs0,fs;//fs0保存初始值,fs用于工作

struct//定义为结构体类型,方便赋值
{
    int available[RN];//系统可用资源向量
}av0,av,avx;//av0保存初始值,av和avx用于工作

pcb proc0[PN],proc[PN];//proc0保存初始值,proc用于工作
int request[RN];//进程请求资源向量

void init();//初始化,输入数据
void output(pcb*);//输出数据
void cur_state();//判断系统当前状态
void req_state();//分析进程提出的请求是否可以响应
void back0();//退回至初始值
void back1(int);//退回至分配前
int check(int*);//进程need向量与available向量比较
int banker();//银行家算法

int main()
{
int num;
printf("【银行家算法】\n");
printf("进程数:%d\n",PN);
printf("资源数:%d\n",RN);
printf("=================\n");
    init();
    output(proc0);//输出初始资源分配情况
    printf("【系统当前状态分析】\n");
    cur_state();
    printf("======================================================\n\n");
    printf("选择操作序号(0:结束程序;1:资源请求分析)\n");
    printf("输入序号:");
    scanf("%d",&num);getchar();
    while(1)
    {
        switch(num)
        {
            case 1:printf("\n【进程资源请求分析】\n");req_state();break;
            default:printf("\n======分析结束!======\n");return 0;
        }
        printf("\n");
        printf("======================================================\n");
        printf("\n");
        printf("选择操作序号(0:结束程序;1:资源请求分析)\n");
        printf("输入序号:");
        scanf("%d",&num);getchar();
    }
}

void init()
{//初始化
int i,j;
    for(i=0;i<PN;i++)
    {
        printf("\n输入进程名:");
        gets(proc0[i].name);
        printf("输入max:");
        for(j=0;j<RN;j++)
            scanf("%d",&proc0[i].max[j]);
        printf("输入allocation:");
        for(j=0;j<RN;j++)
            scanf("%d",&proc0[i].allocation[j]);
        for(j=0;j<RN;j++)//计算need
            proc0[i].need[j]=proc0[i].max[j]-proc0[i].allocation[j];
        fs0.flag[i]=0;//进程标志位置0
        fs0.safes[i]=-1;//安全序列置-1
        proc[i]=proc0[i];//给工作矩阵proc赋值
        getchar();//吸收scanf()产生的回车符
    }
    printf("\n输入available:");
    for(j=0;j<RN;j++)
        scanf("%d",&av0.available[j]);
    fs=fs0;//给工作单元fs和av赋值
    av=av0;
    getchar();//吸收scanf()产生的回车符
}

void output(pcb* p)
{//输出资源分配情况,觉得麻烦可以不考虑
    int i,j;
    printf("\n");
    printf("===============================================================================\n");
    printf(" 标志位 | 进程名 |  最大值 \t|  已分配 \t|  需求值 \t|  可用数 \n");
    printf("-------------------------------------------------------------------------------\n");
    for(i=0;i<PN;i++)
    {
        printf("   %-5d",fs.flag[i]);
        printf("|");
        printf("   %-5s",p[i].name);
        printf("| ");
        for(j=0;j<RN;j++)
            printf("%-3d",p[i].max[j]);
        printf("\t| ");
        for(j=0;j<RN;j++)
            printf("%-3d",p[i].allocation[j]);
        printf("\t| ");
        for(j=0;j<RN;j++)
            printf("%-3d",p[i].need[j]);
        printf("\t| ");
        if(i==0)
            for(j=0;j<RN;j++)
                printf("%-3d",av.available[j]);
        printf("\n");
    }
    printf("===============================================================================\n\n");
}

int banker()
{//银行家算法
    int i,j,t=0,k,f;
    k=0;//计数器,找到符合条件的进程数
    f=1;//标志位,每轮查找标志,f=0时该轮未找到合适进程,查找结束
    while(f==1&&k<PN)
    {
        f=0;//本轮查找标志置0
        for(i=0;i<PN;i++)
            if(!fs.flag[i]&&check(proc[i].need))
            {//找到符合条件的进程
                f=1;//本轮查找标志置1
                fs.flag[i]=1;//进程标志置1
                for(j=0;j<RN;j++)//修改available中的值
                    av.available[j]+=proc[i].allocation[j];
                fs.safes[t]=i;//进程序号i记入safes数组中,作为安全序列输出
                t++;k++;
            }
    }
    if(k<PN)return 0;//当k<PN时说明不存在安全序列,返回0
    else return 1;
}

int check(int* p)//p为当前进程的need向量
{//当前进程need向量与available向量比较
    int i;
    for(i=0;i<RN;i++)
        if(p[i]>av.available[i])return 0;//若检测不通过则返回0
    return 1;//检测通过
}

void cur_state()
{//检测系统当前状态
    int i;
    if(banker())
    {
        printf("分析结果:当前系统处于安全状态,存在安全序列 ");
        for(i=0;i<PN;i++)//输出安全序列
            printf("p%d",fs.safes[i]);
        printf("\n");
    }
    else
        printf("分析结果:当前系统处于不安全状态!请结束程序");
    //output(proc);//输出分析后的状态(查看flag和available状况)
    fs=fs0;av=av0;//退回至初始状态
    printf("\n\n");
}

void req_state()
{//对进程提出的资源请求,判断分配的可行性
    int i,j,n;
    printf("输入提出请求的进程序号n:p");
    scanf("%d",&n);
    printf("输入请求资源向量request:");
    for(i=0;i<RN;i++)
        scanf("%d",&request[i]);
    for(i=0;i<RN;i++)//判断请求的合法性
        if(request[i]>proc[n].need[i]||request[i]>av.available[i])
        {
            printf("分析结果:请求不合法,系统不予响应!");
            for(j=0;j<RN;j++)
                request[j]=0;//清空request
            return;
        }

    for(i=0;i<RN;i++)
    {//尝试分配,修改allocation,need和available的值
        av.available[i]-=request[i];
        proc[n].need[i]-=request[i];
        proc[n].allocation[i]+=request[i];

    }
    avx=av;//avx保存分配后available的值
    //output(proc);//输出分配后的资源分布状况
    if(banker())//调用银行家算法,寻找安全序列
    {
        printf("分析结果:当前系统处于安全状态,存在安全序列 ");
        for(i=0;i<PN;i++)//输出安全序列
            printf("p%d ",fs.safes[i]);
        printf("\n");
        av=avx;//分析结束,确定资源分配
        fs=fs0;//清空标识位flag和安全序列safes
    }
    else
    {
        printf("分析结果:不存在安全序列,系统不予响应,进程阻塞!\n");
        //output(proc);//输出分析结束后的情况(查看flag和available状况)
        back1(n);//取消分配,退回至分配前
        printf("已取消分配,退回至分配前\n");
    }
    printf("\n\n");
    printf("输入“y”可退回到初始状态,请选择(y/n)\n");
    printf("请输入:");
    getchar();//吸收前面的输入所产生的回车符
    if(getchar()=='y')
    {
        back0();
        printf("已退回至初始状态\n");
    }
}

void back0()
{//恢复至初始值
    int i;
    fs=fs0;
    av=av0;
    for(i=0;i<PN;i++)
        proc[i]=proc0[i];
}

void back1(int m)//m为提出资源请求的进程序号
{//撤销分配,退回至分配前
    int i;
    fs=fs0;
    for(i=0;i<RN;i++)
    {
        av.available[i]=avx.available[i]-request[i];
        proc[m].need[i]+=request[i];
        proc[m].allocation[i]-=request[i];
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

比特冬哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值