银行家算法——C语言实现

news2024/10/7 2:27:04

算法思路

将操作系统看作是银行家,操作系统所拥有的资源就相当于银行家所拥有的资产,进程向操作系统申请资源就相当于资产家向银行贷款,规定资产家在向银行贷款之前,先申明其所贷数额的最大值,申明之后其贷款的数额不得超过此最大值,而银行家应该合理安排贷款给各个资产家的顺序,以保证银行不会破产;显然将钱全部分配给一位资本家是十分不合理的这样银行家将承担很大的风险;

算法所用到的数据结构

  1. max[ ][ ]:用于记录进程对系统中各个资源的最大需求量,如max[i][j]表示第i个进程对系统中的Rj资源的最大需求量
  2. allocation[ ][ ]:表示各个进程已经分配到的资源的数目,比如allocation[i][j]表示第i个进程目前分配到资源Rj的数目
  3. available[ ]:表示目前系统中各个资源可用的数量,比如available[i]表示资源Ri此时的可用数量
  4. need[ ][ ]:表示进程此时还需要的各个资源的数量,如need[i][j]表示第i个进程还需要的Rj的资源的数目,显然:need[i][j]=max[i][j]-allocation[i][j];

算法步骤 

假设系统中有三类资源A,B,C,各个资源的数目已知,若此时进程Pi向系统申请资源,其资源申请向量为requesti(x,y,z),即进程i需要A类资源数目x,B类资源数目y,C类资源数目z

  1. 第一步若requesti>need[i](只要存在j,使得requesti[j]>need[i][j],那么此不等式便成立) ,则表明进程i所申请的资源数目大于其一开始所声明的最大值,系统对其请求不予理睬,若此不等式不成立,则继续执行下一步;
  2. 第二步根据allocation数组计算出available,如果request>available(只要存在j,使得requesti[j]>available[j],那么此不等式便成立) ,若该不等式成立则表明此时系统中的剩余资源数目不能满足进程i的请求,进程i必须阻塞等待,若该不等式不成立则继续执行下一步;
  3. 第三步,尝试着将进程i所需要的资源分配给进程i,然后检测若将进程i所需要的资源分配给进程i之后会不会导致系统进入不安全的状态,若不会导致系统进入不安全状态,那么就正式将资源分配给进程i,否则就要将刚刚尝试分配给进程i的资源回收,拒绝进程i的资源请求

上诉算法最关键的一部是最后一步的判断此时系统是否处于安全状态,于是接着介绍系统安全性检测算法

安全性检测算法 

  1. 设置数组work[ ],work数组的初始值是available
  2. 将work[i]数组与need[i[进行比较,若满足work[i]>need[i]那么边将进程i添加到安全序列里面,若不满足则继续扫面下一个进程是否满足此不等式,若满足,则改变work数组的值:work[j]+=allocation[i][j],然后从第一个进程开始扫描,看当改变了work之后是否新增进程满足条件
  3. 若最后安全序列中含有系统中全部的进程那么就说此时系统是安全的

算法源代码

算法详细思路在代码注释中给出

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS


//需要解决的问题:
//1.根据系统现在的状态判断系统现在是不是安全的
//2.当某一个进程像系统请求资源时,判断此时系统应不应该将此资源分配给他


#define RESOURCE_NUM 3
#define PROCESS_NUM 5

#define true 1
#define false 0

//定义系统拥有的各种资源的数量
int maxResource[RESOURCE_NUM];

//定义系统中剩余可用的资源数目
int available[RESOURCE_NUM];

//定义安全检测时的work数组
int work[RESOURCE_NUM];

//定义系统中现在已经分配给各个进程的资源数目
int allocation[PROCESS_NUM][RESOURCE_NUM];

//定义各个进程对资源的最大需求量
int maxNeeds[PROCESS_NUM][RESOURCE_NUM];

//定义各个进程还需要的各个资源的数目
int stillNeeds[PROCESS_NUM][RESOURCE_NUM];


//用于定义系统中存在的安全序列
int securitySequence[PROCESS_NUM];


//isEnougth[i]表示系统中的剩余资源可以满足进程i还需要的资源数目
int isEnough[PROCESS_NUM];


//定义用于对各个数组模块进行初始化的函数
void initialize();


//用于打印目前系统的资源分配情况
void outAllocation();


//用于求解stillNeeds函数
void solveNeeds();


//用于求解系统中剩余资源数目的函数
void solveAvailable();


//定义打印安全序列的代码
void print();


//安全性检测算法
int securityTest();


//定义用于给请求进程进行资源分配的函数
int dispense();


//定义用于将分配给某个进程的资源回收的函数
int restore();


//银行家算法,用于判断当此时系统中有进程申请系统资源时能不能将其所申请的资源分配给他
void banker();


//用于记录此时是那个进程请求系统为其分配资源
int requestProcess;   


//用于记录进程所请求的各种系统资源的数目
int request[RESOURCE_NUM];  


int main()
{
	initialize();
	//打印当前系统的资源分配情况
	outAllocation();

	printf("\n\n");

	banker();

	printf("\n\n");

	//执行银行家算法之后由于可能给某个进程分配了资源,于是再次打印系统目前的资源分配清苦
	outAllocation();

	return 0;
}


void solveNeeds()
{
	for (int i = 0; i < PROCESS_NUM; i++)
	{
		for (int j = 0; j < RESOURCE_NUM; j++)
		{
			stillNeeds[i][j] = maxNeeds[i][j] - allocation[i][j];
		}
	}
}


void solveAvailable()
{
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		available[i] = maxResource[i];
	}
	for (int j = 0; j < RESOURCE_NUM; j++)    //j表示列
	{
		for (int i = 0; i < PROCESS_NUM; i++)    //i表示行
		{
			available[j] -= allocation[i][j];
		}
	}
}


void initialize()
{
	//初始化系统中各个资源的数量
	printf("请输入系统中各种资源的数量:\n");
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		scanf("%d", &maxResource[i]);
	}


	//初始化各个进程对系统中各个资源的最大需求量
	for (int i = 0; i < PROCESS_NUM; i++)
	{
		printf("请输入进程%d对系统中各种资源的最大需求量:\n", i);
		for (int j = 0; j < RESOURCE_NUM; j++)
		{
			scanf("%d", &maxNeeds[i][j]);
		}
	}


	//初始化allocation矩阵
	for (int i = 0; i < PROCESS_NUM; i++)
	{
		printf("系统已经分配给进程%d的各种资源的数量:\n", i);
		for (int j = 0; j < RESOURCE_NUM; j++)
		{
			scanf("%d", &allocation[i][j]);
		}
	}


	//初始化需求矩阵
	solveNeeds();


	//初始化available数组
	solveAvailable();


	//初始化work数组
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		work[i] = available[i];
	}


	//初始化isEnough数组
	for (int i = 0; i < PROCESS_NUM; i++)
	{
		isEnough[i] = false;
	}


	printf("请输入当前是哪一个进程在向系统申请资源\n");
	scanf("%d", &requestProcess);


	printf("请输入进程%d向系统申请的各个资源的数目\n", requestProcess);
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		scanf("%d", &request[i]);
	}
}

void outAllocation()
{
	printf("**************************************************************************************************\n");
	printf("当前系统的资源分配情况如下:\n");
	printf("\t\tmaxNeeds\t\tallocation\t\tstillNeeds\t\tavailable\n");
	printf("资源名称\t");

	for (int i = 0; i < 4; i++)
	{
		
		if (i == 3)
		{
			for (int j = 0; j < RESOURCE_NUM; j++)
			{
				printf("%d ", available[j]);
			}
		}
		else
		{
			printf("A B C");
			printf("\t\t\t");
		}

	}

	printf("\n");

	for (int j = 0; j < PROCESS_NUM; j++)
	{
		printf("P%d\t\t",j);
		for (int k = 0; k < RESOURCE_NUM; k++)
		{
			printf("%d ", maxNeeds[j][k]);
		}
		printf("\t\t\t");

		for (int k = 0; k < RESOURCE_NUM; k++)
		{
			printf("%d ", allocation[j][k]);
		}
		printf("\t\t\t");

		for (int k = 0; k < RESOURCE_NUM; k++)
		{
			printf("%d ", stillNeeds[j][k]);
		}

		printf("\n");
	}

	printf("**************************************************************************************************\n");
}


void print()
{
	for (int i = 0; i < PROCESS_NUM; i++)
	{
		if (i == PROCESS_NUM - 1)
			printf("%d", securitySequence[i]);
		else
			printf("%d->", securitySequence[i]);
	}
	printf("\n");
}


int securityTest()
{
	int count = 0;  //用于记录安全序列中已经添加了多少个进程


	for (int i = 0; i < PROCESS_NUM; i++)
	{
		int flag = 1;  //用于标记是否使用break语句跳出了内层循环
		for (int j = 0; j < RESOURCE_NUM; j++)
		{
			if (work[j] < stillNeeds[i][j])
			{
				flag = 0;
				break;
			}
		}


		//若isEnough[i]=0表示此时的进程i还没有被加入到安全序列中,那么便可以将其加入到安全序列中
		if (flag == 1 && isEnough[i] == false)
		{
			//将进程i添加到安全序列中
			securitySequence[count] = i;
			count++;


			//修改isEnough[i]的值为true,有两层含义,第一层含义是代表此时进程i已经进入安全序列了,下一次循环检测时若检测到进程i便可以不用重复将其加入到安全序列中
			//第二层含义,是最后用于判定系统是否安全的依据,只有isEnough数组中全部的元素的值都是1才代表着此系统是安全的否则系就处于不安全的状态
			isEnough[i] = true;


			//当安全序列中新增进程之后,需要改变available数组的值
			for (int k = 0; k < RESOURCE_NUM; k++)
			{
				work[k] += allocation[i][k];
			}

			i = -1;
			//保证可以从头开始遍历所有的进程
			//注意此条语句的位置必须位于此,因为只有安全序列中添加了新元素之后,available数组的值才会改变,此时才需要重新扫描所有进程看如今系统中剩余的资源是否可以满足以前不能满足的进程
		}
	}


	//检查系统此时是否处于安全状态
	for (int i = 0; i < PROCESS_NUM; i++)
	{
		if (isEnough[i] == false) {
			return false;
		}
	}
	return true;

}

int dispense()
{
	//尝试将资源分配给请求进程的时候,发生改变的数组有,allocation,stillNeeds,available,work;
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		allocation[requestProcess][i] += request[i];
		stillNeeds[requestProcess][i] -= request[i];
		available[i] -= request[i];
		work[i] -= request[i];
	}
}

int restore()
{
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		allocation[requestProcess][i] -= request[i];
		stillNeeds[requestProcess][i] += request[i];
		available[i] += request[i];
		work[i] += request[i];
	}
}


void banker()
{
	//第一步检查进程所申请的资源数目是否超过其一开始声明的最大值
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		if (request[i] > stillNeeds[requestProcess][i])
		{
			printf("进程%d所申请的资源已经超过了其一开始定义的最大值,不予分配\n");
			return;
		}
	}


	//第二检查系统中剩余的资源是满足进程的请求
	for (int i = 0; i < RESOURCE_NUM; i++)
	{
		if (request[i] > available[i])
		{
			printf("系统资源不足,分配失败,请进程阻塞等待\n");
			return;
		}
	}


	//尝试分配资源
	dispense();


	//分配完资源之后判断系统是否处于安全状态,若处于安全状态则就真正的将资源分配给请求的进程,否则就将刚才预分配的资源恢复
	if (securityTest())
	{
		printf("此次分配不会导致系统进入不安全状态,分配成功!\n");
		//输出此时的安全序列
		printf("此时系统的其中一个安全序列为:\n");
		print();
		return;
	}
	else
	{
		printf("此次分配将会使得系统进入不安全状态,拒绝分配\n");
		restore();
		return;
	}
}



运行结果截图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1034466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习-一个简单的深度学习推导

文章目录 前言1.sigmod函数2.sigmoid求导3.损失函数loss4.神经网络1.神经网络结构2.公式表示-正向传播3.梯度计算1.Loss 函数2.梯度1.反向传播第2-3层2.反向传播第1-2层 前言 本章主要推导一个简单的两层神经网络。 其中公式入口【入口】 1.sigmod函数 激活函数我们选择sigmo…

银河麒麟ky10 server sp3下载

下载路径 /操作系统/Kylin-Server-V10-SP3-General-Release-2212-X86_64.iso

(高阶) Redis 7 第15讲 布隆过滤器 BitMap篇

面试题 如何快速准备判断某一数据在海量数据中存在了解布隆过滤器吗安全网址判断,黑名单校验,识别垃圾邮件白名单校验,识别合法用户?理论 由一个初始值都为0的 bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素 设计思想 目的减少内存占用方式不保存数据信…

巨人互动|Facebook海外户Facebook运营工具有哪些?

Facebook是全球最大的社交媒体平台之一&#xff0c;为企业提供了丰富的运营工具和功能&#xff0c;帮助他们在这个庞大的平台上推广、管理和监测他们的业务。下面小编讲一些常用的Facebook运营工具吧&#xff01; 1、Facebook广告管理 Facebook提供了强大的广告管理平台&#…

【从0学习Solidity】24. 在合约中创建新合约

【从0学习Solidity】 24. 在合约中创建新合约 博主简介&#xff1a;不写代码没饭吃&#xff0c;一名全栈领域的创作者&#xff0c;专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构&#xff0c;分享一些项目实战经验以及前沿技术的见解。关注我们的主页&#xff…

多维时序 | MATLAB实现WOA-CNN-GRU-Attention多变量时间序列预测(SE注意力机制)

多维时序 | MATLAB实现WOA-CNN-GRU-Attention多变量时间序列预测&#xff08;SE注意力机制&#xff09; 目录 多维时序 | MATLAB实现WOA-CNN-GRU-Attention多变量时间序列预测&#xff08;SE注意力机制&#xff09;预测效果基本描述模型描述程序设计参考资料 预测效果 基本描述…

【Tomcat】Tomcat 运行原理

Tomcat 运行原理 一. Servlet 运行原理1. 接收请求2. 根据请求计算响应3. 返回响应 二. Tomcat 的伪代码1. Tomcat 初始化流程2. Tomcat 处理请求流程3. Servlet 的 service 方法的实现 一. Servlet 运行原理 在 Servlet 的代码中我们并没有写 main 方法, 那么对应的 doGet 代…

Linux 性能分析笔记:平均负载的理解

文章目录 uptime 的命令解释uptime 平均负载的理解man uptime平均负载的合理值系统负载的趋势 案例分析CPU 密集型程序IO 密集型大量进程 学习笔记主要来源&#xff1a;Linux性能优化实战_Linux_性能调优-极客时间 uptime 的命令解释 uptime 09:17:52 系统当前时间up 1 day, 1…

Servlet开发-tomcat如何解析json格式的数据

前言 在应用层协议中&#xff0c;json格式是程序猿经常用来组织数据的格式&#xff0c;在http数据报的body中也经常会携带json格式的数据&#xff0c;所以 tomcat 部署的 webapp 能够解析 json 格式的数据是很有必要的 引入依赖 tomcat 本身并不支持解析 json 格式的数据&…

【Qt】16进制转换格式字符串及二进制

【Qt】16进制转换格式字符串及二进制 16进制转换成字符串16进制转换成格式字符串16进制转换成字符串并每两位加空格16进制转换成二进制 16进制转换成字符串 可调用QString类的静态方法number(),此方法为重载&#xff0c;有以下重载 // 第一个参数为输入值&#xff0c;第二个为…

如何接入电商数据平台API接口实现数据采集请求获取商品详情价格、优惠券、优惠活动、品牌、店铺、主图等数据示例

app商品详情原数据API接口可以获取拼多多平台上某个商品的详细信息&#xff0c;包括商品标题、价格、图片、规格、参数、店铺信息等。 通过这个接口获取到的商品详情数据可以结合其他数据进行深度挖掘&#xff0c;例如可以将商品数据对比分析&#xff0c;找出同类商品中的优劣…

Unity中Shader中UI材质去色功能实现

文章目录 前言一、实现思路1、在属性面板暴露一个 开关 来控制去色变体2、声明一个变体3、在片元着色器实现去色 二、实现1、定义开关2、声明变体3、在片元着色器中&#xff0c;使用宏判断是否去色法1、只输出结果的单通道值&#xff0c;一般来说结果不太理想&#xff0c;比较节…

TikTok扮演丘比特为员工提供婚介服务

据透露&#xff0c;TikTok 有一项内部配对服务&#xff0c;供员工将同事介绍给朋友和家人。 该频道名为 Meet Cute&#xff0c;是全球数千名 TikTok 员工使用的工作场所工具&#xff0c;用于文件托管和视频会议。它还可以帮助人们从同事中找到潜在的浪漫伴侣。 在该平台上&…

html页面仿word文档样式(vue页面也适用)

目录 文章title&#xff1a; 标题&#xff1a; 正文&#xff1a; 完整代码&#xff1a; 页面效果&#xff1a; 文章title&#xff1a; <div><h3 style"display: flex;justify-content: center; align-items: center; color: #000;">实验室招新报名公…

CSDN程序设计精品课程——Java程序设计(Java语言概述·Java语言基础·Java基本数据类型)

Java程序设计课程分配&#xff1a; Java语言概述Java语言基础Java基本数据类型控制结构Java核心类类的定义与使用对象的初始化包继承抽象类与接口异常的处理自定义异常字节流字符流标准输入/输出流基本类型的包装类型泛型和集合类 目录 Java语言概述 Java语言的特点 Java开发…

初学Java小案例(一)

目录 案例一&#xff1a;买飞机票 案例二&#xff1a;开发验证码 案例三&#xff1a;评委打分 案例四&#xff1a;数字加密 案例五&#xff1a;数组拷贝 案例六&#xff1a;抢红包 案例七&#xff1a;找素数的三种方法 案例八&#xff1a;打印乘法口诀表 案例九&#x…

el-image 和 el-table冲突层级冲突问题

其中原理&#xff0c;很多博客已经所过了&#xff0c;table组件中使用图片&#xff0c;会出现层级过低问题&#xff0c; 网上大部分解决方式是 使用穿透 // 单元格样式 ::v-deep(.el-table__cell) {position: static !important; }我在此不推荐这种解决方式&#xff0c;原因&a…

如何编写测试用例,一篇搞定

前言 说到测试用例&#xff0c;但凡是软件测试从业人员&#xff0c;都不会陌生。但对于测试新手来说&#xff0c;测试用例仍旧有遗漏&#xff0c;或者写不好的时候。那么&#xff0c;究竟应该如何写好测试用例呢&#xff1f;今天就来针对性的聊聊这个话题。 在分析如何写测试…

初识Java 10-3 集合

目录 Collection和Iterator的对比 for-in和迭代器 总结图 本笔记参考自&#xff1a; 《On Java 中文版》 Collection和Iterator的对比 Collection是所有序列集合的共同根接口。因此&#xff0c;可以认为它是一个为表示其他接口之间的共性而出现的“附属接口”。 java.util.Ab…