《操作系统》银行家算法c++代码实现

前言:
看了一篇博客,感觉算法实现的意思跟我想的不一样,又不想继续看别的代码了。索性就自己写了一个我所理解的,供大家参考
这里不介绍银行家算法的概念,重点放在代码实现上
想要看银行家算法的前置知识和概念可以看(复制进入)https://www.cnblogs.com/wkfvawl/p/11929508.html

  • 说说我的算法的效果:
    • 输入一系列进程对于资源的申请,如果不合法(申请的比需要的多),忽略
    • 如果合法且目前能分配,那么尝试分配,然后安全性检查。如果安全就分配,否则取消分配
    • 如果合法但目前不能分配,就先留着,以后再看看能不能分配
    • 来一个资源申请就处理一个,而不是收到所有申请之后再依次处理。换句话说,处理第i个资源申请的时候,我们不会考虑i后面还未收到的资源申请

如果你想实现的效果和我的一样,那么可以继续看下去

  • 由系统安全的定义可知,只要存在一个安全序列,那么系统就是安全的,因此我们只需找到一个安全序列就好
  • 因此就像深度优先找出迷宫出口一样,我的算法借鉴DFS的思想,递归实现
  • 我的不一定对,只是通过了老师给的用例,我自己在老师的用例上改进的用例以及<操作系统>罗宇书上的算法用例,就算错了能给大家一点启发也是不错的~(实际上自从发布之后,这篇随笔改了至少七八次,怕误导别人hh
  • 我们的实验要求是输出安全序列,输出稍微改改就行,核心一样

输入用例格式

以下是老师给的输入用例

5 3
10 5 7
0 0 1 0 7 5 3
1 2 0 0 3 2 2
2 3 0 2 9 0 2
3 2 1 1 2 2 2
4 0 0 2 4 3 3
1 1 0 2
4 3 3 0
0 0 2 0

以下是我的改进输入用例

5 3
10 5 7
0 0 1 0 7 5 3
1 2 0 0 15 2 2
2 3 0 2 9 0 2
3 2 1 1 2 2 2
4 5 0 2 8 3 3
1 13 0 2
4 3 3 1
0 0 2 0

以下是课本上给出的用例(要测试的话,代码里的num记得改

5 3
10 5 7
0 0 0 0 9 0 0
1 0 0 0 8 0 0
2 0 0 0 0 0 0
3 0 0 0 0 0 0
4 0 0 0 3 0 0
1 4 0 0
4 2 0 0
0 2 0 0
4 1 0 0
1 4 0 0
0 7 0 0

代码解释

  • 最开始我还在想,为什么安全检查函数书上要求多设work和finish数组,现在看来是很有必要的。
    • 用work代替available,就是在available的副本上模拟尝试分配,不安全的话可以随时退出安全检查函数,反正不影响available数组,方便。直接在available改的话,要是尝试分配失败了,还要把数组恢复回来。函数里needed,finished,allocationed一样的道理
    • finish保存目前还有哪些进程没有在安全序列,我们需要将资源尝试分配给不在安全序列里的进程。从输入中可以看到,不是所有进程都申请了资源的,因此可以让没申请资源的进程一直待在安全序列里,这样就不用管他们了
  • 我就实现了两个函数,show用于展示当前系统资源,进程所占资源,进程还需要的资源之类的信息,方便调试,这个不用管;test函数用于检查满足进程i的需求后系统是否安全

以下是实现代码

#include<iostream>
using namespace std;
int n, m;//进程数和资源数
int available[10];//available[j]=k,表示系统有k个j类资源
int Max[10][10];//max[i][j]=k,表示进程i最多申请k个j类资源
int allocation[10][10];//allocation[i][j]=k,表示进程i已有k个j类资源
int need[10][10];//need[i][j]=k,表示i进程还需要k个j类资源
int request[10][10];//requst[i][j]=k,表示进程i正在申请k个j类资源
int finish[10];//finish[i]=1,表示进程i已经在安全队列中
void show()//方便调试写的,不过显示的是available而不是work,不能直接调用
{
	cout << "\t\tallocation\t\tneed\t\tmax\t\tavailable" << endl;
	for (int i = 0; i < n; i++)
	{
		cout << "进程" << i << "\t\t";
		for (int j = 0; j < m; j++)
			cout << allocation[i][j] << " ";
		cout << "\t\t\t";
		for (int j = 0; j < m; j++)
			cout << need[i][j] << " ";
		cout << "\t\t";
		for (int j = 0; j < m; j++)
			cout << Max[i][j] << " ";
		cout << "\t\t";
		for (int j = 0; j < m; j++)
			cout << available[j]<<" ";
		cout << endl;
	}
}
int test(int availabled[],int finisheded[],int neededed[10][10],int allocationeded[10][10],int i)//满足进程i的请求,检查所有进程是否在安全队列,都在返回1,否则返回0
{
	int finished[10],worked[10],needed[10][10],allocationed[10][10];//为了不改变finish,available和need,那我用复制品
	for (int a = 0; a < 10; a++)
	{
		finished[a] = finisheded[a];
		worked[a] = availabled[a];
		for (int id = 0; id < 10; id++)
		{
			needed[id][a] = neededed[id][a];
			allocationed[id][a] = allocationeded[id][a];
		}
	}

	//模拟一下满足
	int release = 1;
	for (int a = 0; a < m; a++)
	{
		worked[a] -= request[i][a];
		needed[i][a] -= request[i][a];
		allocationed[i][a] += request[i][a];
		if (worked[a] < 0)return 0;//因为函数内部进入递归时没有判断条件,所以这里需要判断,资源不够了,不能分配资源
		if (needed[i][a])release = 0;
	}
	//如果进程已有所有资源可以执行,模拟一下执行完的时候,占用的资源还给系统的过程
	if (release)
	{
		for (int a = 0; a < m; a++)
		{
			worked[a] += allocationed[i][a];
			needed[i][a] = 0;
			allocationed[i][a] = 0;
		}
	}
	finished[i] = 1;//无论能否释放资源,我们都应该放入安全序列,因为这个资源申请我们已经处理了
	
	int flag;
	for (int a = 0; a < n; a++)//寻找不在序列里的进程时,需要不断从头遍历finished数组,因此要二重循环,从头遍历个n次就够了
	{
		flag = 0;//判断是否所有进程在安全队列中,如果是,可以退出循环了
		for (int b = 0; b < n; b++)
		{
			if (finished[b])//如果b进程已经在队列了
				continue;
			flag = 1;//如果不在队列,满足它
			if (test(worked,finished,needed, allocationed,b))//如果满足就安全了,那么找到了安全队列
				finished[b]=1;
		}
		if (!flag) break;
	}
	if (!flag)return 1;
	else return 0;
}
int main()
{
	cin >> n >> m;
	for (int i = 0; i < m; i++)//读入进程和资源数,默认资源从0开始命名
		cin >> available[i];
	for (int i = 0; i < n; i++)//初始化矩阵值
	{
		int id;
		cin >> id;
		for (int j = 0; j < m; j++)
			cin >> allocation[id][j];
		for (int j = 0; j < m; j++)
			cin >> Max[id][j];
		for (int j = 0; j < n; j++)
			need[id][j] = Max[id][j] - allocation[id][j];
		finish[i] = 1;//假设所有进程都已经在安全队列里
	}

	//开始处理资源申请,假设有三个申请,如果要测试书上用例,改成6就好
	int num = 3;
	for (int i = 0; i < num; i++)
	{
		
		int id, invalid = 0, wait = 0;
		cin >> id;
		finish[id] = 0;//id进程此时未加入队列
		//读入数据
		for (int j = 0; j < m; j++)
		{
			cin >> request[id][j];
			if (request[id][j] > need[id][j])
				invalid = 1;
			else if (request[id][j] > available[j])
				wait = 1;
		}
		//如果输入不合法
		if (invalid)
		{
			cout << "进程" << id << "输入不合法" << endl;
			for (int j = 0; j < m; j++)//当这次申请不存在
				request[id][j] = 0;
			continue;
		}
		//如果目前满足不了进程
		if (wait)
		{
			cout << "进程" << id << "资源不够再等等" << endl;
			continue;
		}
		if (test(available, finish, need, allocation,id))//输入合法且资源够,那分配试试
		{
			cout << "进程" << id << "可以分配" << endl;
			//这波真分配
			int  release = 1;
			for (int a = 0; a < m; a++)
			{
				available[a] -= request[id][a];
				need[id][a] -= request[id][a];
				allocation[id][a] += request[id][a];
				if (need[id][a])release = 0;
			}
			//如果资源满足了可以执行,执行完记得还给系统
			if (release)
			{
				for (int a = 0; a < m; a++)
				{
					//available[a] += request[id][a];
					available[a] += allocation[id][a];
					need[id][a] = 0;
					allocation[id][a] = 0;
				}
			}
			finish[id] = 1;//就算不能释放,也要加入安全序列,因为我们已经处理了这个资源申请
		}
		else cout << "进程"<<id<<"现在还不能分配" << endl;
		for (int i = 0; i < n; i++)//看看别的进程能不能分配
		{
			if (finish[i]==0&&test(available, finish, need, allocation,i))
			{
				int  release = 1;
				cout << "进程" << i << "可以分配" << endl;
				//这波真分配
				for (int a = 0; a < m; a++)
				{
					available[a] -= request[i][a];
					need[i][a] -= request[i][a];
					allocation[i][a] += request[i][a];
					if (need[i][a])release = 0;
				}
				//如果资源满足了可以执行,执行完记得还给系统
				if (release)
				{
					for (int a = 0; a < m; a++)
					{
						//available[a] += request[id][a];
						available[a] += allocation[id][a];
						need[id][a] = 0;
						allocation[id][a] = 0;
					}
				}
				finish[i] = 1;//就算不能释放,也要加入安全序列,因为我们已经处理了这个资源申请
			}
		}
	}
	return 0;
}

和DFS对比

去掉test函数里模拟分配资源和释放资源的步骤,只看第三步的核心代码,是否有点相似呢

以下是老师用例运行结果

以下是我的改进用例运行结果

以下是书上用例的结果

posted @   穿过雾的阴霾  阅读(1018)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示