操作系统——银行家算法实现

本文深入解析银行家算法,包括算法中的关键数据结构如最大需求矩阵、分配矩阵等,以及安全性检查算法的具体实现步骤。通过一个C++代码示例,详细说明了如何在实际应用中实现银行家算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

银行家算法思想:

1.银行家算法中的数据结构:

(1)可利用资源向量Available。这是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态地改变。
 如果Available[j]=K,则表示系统中现有Rj类资源K个。

(2)最大需求矩阵Max。这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。

(3)分配矩阵Allocation。这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。

如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的数目为K。

(4)需求矩阵Need。这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。

上述三个矩阵间存在下述关系:
Need[i, j]=Max[i, j]-Allocation[i, j]

2.系统所执行的安全性算法可描述如下:

(1) 设置两个向量:

①工作向量Work,它表示系统可提供给进程继续运行所需的各类资源数目,它含有m个元素,在执行安全算法开始时,Work:=Available。

②Finish,它表示系统是否有足够的资源分配给进程,使之运行完成。开始时先做Finish[i]:=false;当有足够资源分配给进程时,再令Finish[i]:=true。

(2) 从进程集合中找到一个能满足下述条件的进程:

  ① Finish[i]=false;
  ② Need[i,j]≤Work[j];若找到,执行步骤(3),否则,执行步骤(4)。

(3) 当进程Pi获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:

Work[j]:= Work[j]+Allocation[i,j];
Finish[i]:=true;
go to step (2);
(4) 如果所有进程的Finish[i]=true都满足,则表示系统处于安全状态;否则,系统处于不安全状态。

3.申请资源:

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

  (1) 如果Request i[j]<=Need[i,j],便转向步骤(2);否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。

  (2) 如果Request i[j]≤Available[j],便转向步骤(3);否则,表示尚无足够资源,Pi须等待。

  (3) 系统试探着把资源分配给进程P i,并修改下面数据结构中的数值:

                Available[j]:= Available[j]-Request i[j];

                Allocation[i,j]:= Allocation[i,j]+Request i[j];

                Need[i,j]:= Need[i,j]-Request i[j];
  (4) 系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待。


一开始我是按照老师给的PPT上的具体操作过程写的,但是可能是我当时对银行家算法的具体实现步骤和其中的安全性检查算法不太了解,认为只有在申请资源之后才需要安全性检查,而且当时写的安全性检查的代码中对循环操作也有错,导致运行错误。

然后我上网找了下讲解银行家算法的视频,跟着视频里的步骤来,算是懂了一些,然后知道了之前出现错误的部分原因,我理解的具体操作如下:

1.根据输入的Max数组、Allocation数组以及Available数组,通过运算得到Need数组、更新了的Available数组;

2.然后进行安全性检查,判断此时程序是否安全;

3.输入申请的资源,然后预分配之后,进行安全性检查,安全则分配,不安全则取消分配。(其中申请资源可能会有多次)


而安全性检查算法是我觉得最绕的:

首先要遍历一下所有的进程,找到所需资源比Available数组中资源数小的进程,然后再实施资源预分配,然后再用Finish数组存储分配结果,最后如果每个进程都是true,则安全。

这几句话虽然说着感觉很好懂,但是到我具体操作的时候,我就一直觉得这个循环很绕,很难理清楚,然后参照了一下网上的关于这部分的代码在算是弄懂了一些。


代码如下:

#include <iostream>
using namespace std;
const int MAXN = 105;
int Available[MAXN];//可利用资源向量
int Max[MAXN][MAXN];//最大需求矩阵
int Allocation[MAXN][MAXN];//分配矩阵
int Need[MAXN][MAXN];//需求矩阵
int Request[MAXN][MAXN];//进程的请求矩阵
int Work[MAXN];//工作向量
bool Finish[MAXN];//表示系统是否有足够的资源分配给进程,使之运行完成
int m, n;//m为可用资源个数,n为进程个数
int *safe_array = new int[n];//存储安全序列
void init()//初始化
{
	cout << "请输入可用资源个数和进程个数:" << endl;
	cin >> m >> n;
	cout << "数组Available[i]表示第i类资源的个数,请依次输入:" << endl;
	for (int i = 1; i <= m; i++)
	{
		//cout << "Available[" << i << "]=  ";
		cin >> Available[i];
	}
	cout << "数组Max[i][j]表示进程i需要第j类资源的最大数目,请依次输入:" << endl;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			//cout << "Max[" << i << "][" << j << "]=  ";
			cin >> Max[i][j];
		}
	cout << "数组Allocation[i][j]表示进程i当前已经分得第j类资源的数目,请依次输入:" << endl;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			//cout << "Allocation[" << i << "][" << j << "]=  ";
			cin >> Allocation[i][j];
			Need[i][j] = Max[i][j] - Allocation[i][j];
			Available[j] -= Allocation[i][j];//更新当前可用资源数组
		}
	cout << "数组Need[i][j]表示进程i需要j类型的资源的数目,请依次输入:" << endl;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			//cout << "Need[" << i << "][" << j << "]=  ";
			cin >> Need[i][j];
		}
}
bool security()//判断系统是否安全
{
	for (int i = 1; i <= m; i++)//资源数m循环
		Work[i] = Available[i];//RIGHT
	for (int j = 1; j <= n; j++)//进程nFinish数组初始化
		Finish[j] = false;//必须在每次安全性检查之前初始化Finish数组   !!!!
	int p = 0;//p是安全序列safe_array数组的下标
	//安全序列检查的第一种写法
	for (int i = 1; i <= n; i++)//进程循环
	{
		int cnt = 0;//记录i进程的满足条件的资源数(之前的代码中忽略了要每个进程的所有的所需资源都要满足条件这个问题)
		for (int j = 1; j <= m; j++)//资源循环
		{
			if (!Finish[i] && Need[i][j] <= Work[j])//满足条件
				cnt++;
			if (cnt == m)//进程i的所需资源全部满足条件,则分配资源
			{
				for (int k = 1; k <= m; k++)
					Work[k] += Allocation[i][k];
				Finish[i] = true;
				safe_array[p++] = i;
				i = 0;//检查前面是否有满足情况的进程(很重要)
					  //与PPT中的执行顺序不太一样,PPT中是先找剩下的中间最小的先看是否满足条件,而这里是先找进程序号在前面的进程是否满足条件
			}
		}
	}
	for (int i = 1; i <= n; i++)//看是否每个进程的Finish数组是否为true,是否有安全序列
		if (!Finish[i])
		{
			cout << "当前系统不安全!" << endl;
			return false;
		}
	cout << "当前系统安全!" << endl;
	cout << "安全序列为:" << endl;
	for (int i = 0; i < n - 1; i++)
		cout << "P" << safe_array[i] - 1 << "->";
	cout << "P" << safe_array[n - 1] - 1 << endl;
	return true;

	//安全序列检查的第二种写法
	//for (int i = 1; i <= n; i++)//进程循环遍历
	//{
	//	bool flag1 = false;//标记是否还存在Finish[i]=false&&Need[i][j]<=Work[j]
	//	for (int j = 1; j <= n; j++)//进程循环遍历
	//	{
	//		if (Finish[j])
	//			continue;
	//		bool flag2 = true;//标记该进程是否满足Finish[i]=false&&Need[i][j]<=Work[j]
	//		for (int k = 1; k <= m; k++)//资源循环遍历
	//		{
	//			if (Need[j][k] > Work[k])
	//				flag2 = false;
	//		}
	//		if (flag2)//满足条件的进程加入安全序列中
	//		{
	//			flag1 = Finish[j] = true;
	//			safe_array[p++] = j - 1;
	//			for (int k = 1; k <= m; k++)//资源循环遍历
	//			{
	//				Work[k] += Allocation[j][k];
	//			}
	//			break;
	//		}
	//	}
	//}
}
void m_request()//接受请求
{
	int i;
	bool flag1 = false;//flag1标记申请的资源数是否超过它所需要的资源数量
	bool flag2 = false;//flag2标记申请的资源数是否超过了当前所能使用的资源数量
	cout << "请输入申请资源的进程号:" << endl;
	cin >> i;
	cout << "请依次输入申请的资源数目:" << endl;
	int k = i + 1;
	for (int j = 1; j <= m; j++)
	{
		cin >> Request[k][j];
		if (Request[k][j] > Need[k][j])//PPT上有误
			flag1 = true;
		if (Request[k][j] > Available[j])
			flag2 = true;
	}
	if (flag1 || flag2)//判断并输出不能执行的原因
	{
		if (flag1)
			cout << "WRONG	申请的资源数量超过了该进程所需要的资源数量!" << endl;
		else if (flag2)
			cout << "WRONG	申请的资源数量超过了当前所能使用的资源数量!进程" << i << "进入等待状态!" << endl;
		else
			cout << "WRONG	申请的资源数量超过了该进程所需要的资源数量或者当前所能使用的资源数量!进程" << i << "进入等待状态!" << endl;
	}
	else//尝试分配资源并判断
	{
		for (int j = 1; j <= m; j++)//分配资源
		{
			Available[j] -= Request[k][j];
			Allocation[k][j] += Request[k][j];
			Need[k][j] -= Request[k][j];
		}
		if (security())//分配不成功
			cout << "分配资源成功!" << endl;
		else
		{
			cout << "分配资源失败,进程" << i << "进入等待状态!" << endl;
			for (int j = 1; j <= m; j++)//复原
			{
				Available[j] += Request[k][j];
				Allocation[k][j] -= Request[k][j];
				Need[k][j] += Request[k][j];
			}
		}
	}
}
void main()
{
	init();
	if (security())
	{
		int a;//存储操作编号
		cout << "请输入操作序号,查询当前资源分配情况(1),请求资源(2),结束此次操作(3):" << endl;
		cin >> a;
		switch (a)
		{
		case 1:
			break;
		case 2:
		{
			int r_n;//申请资源次数
			cout << "请输入申请资源次数" << endl;
			cin >> r_n;
			while (r_n--)
				m_request();
			break;
		}
		case 3:
		default:
			cout << "此次操作结束!" << endl;
			break;
		}
		
	}
	else
	{
		cout << "本次操作无效" << endl;
	}
}

运行结果:

参考:银行家算法实现

5 银行家算法实现 5.1 实验类型 设计型(4学时)。 5.2 实验目的 1) 理解死锁避免相关内容; 2) 掌握银行家算法主要流程; 3) 掌握安全性检查流程。 5.3 实验描述 本实验主要对操作系统中的死锁预防部分的理论进行实验。要求实验者设计一个程序,该程序可对每一次资源申请采用银行家算法进行分配。 5.4 实验内容 1) 设计多个资源(≥3); 2) 设计多个进程(≥3); 3) 设计银行家算法相关的数据结构; 4) 动态进行资源申请、分配、安全性检测并给出分配结果。 5.5 实验要求 1) 编写程序完成实验内容; 2) 画出安全性检测函数流程图; 3) 撰写实验报告。 5.6 测试要求 1) 进行Request请求,输入参数为进程号、资源号和资源数; 2) 进行3次以上的Request请求; 3) 至少进行1次资源数目少于可用资源数,但不安全的请求。 5.7 相关知识 5.7.1 银行家算法的数据结构 1) 可利用资源向量Available。其中每个元素代表每类资源的数目。 2) 最大需求矩阵Max。其中每个元素代表每个进程对于每类资源最大需求量。Max[i,j]=K表示i进程对于j类资源最大需求量为K。 3) 分配矩阵Allocation。其中每个元素代表每个进程已得到的每类资源的数目。 4) 需求矩阵Need。其中每个元素代表每个进程还需要的每类资源的数目。 5.7.2 银行家算法 Request i [j]=K表示进程Pi需要K个j类资源。 1) 如果Request i [j]≤Need[i , j],便转向步骤2,否则认为出错。 2) 如果Request i [j]≤Available[j],便转向步骤3,否则表示无足够资源,Pi需等待; 3) 系统尝试分配资源给Pi; 4) 系统进行安全性检查,检查此次资源分配后,系统是否安全。如果安全,则正式分配资源,否则撤销此次分配。 5.7.3 安全性算法 1) 设置两个向量:工作向量Work和Finish。算法开始时Work=Available;Finish表示系统是否有足够的资源分配给进程,使之运行完成,开始时,令Finish[i]=False;如果有足够的资源分配给进程,则令Finish[i]=True。 2) 从进程集合中找到一个能满足下列条件的进程:Finish[i]=False;Need[i,j] ≤ Work[j],若找到,执行步骤3),否则,执行步骤4); 3) Pi获得所需资源后,可顺利执行指导完成,并释放它占有的资源。并执行: Work[j]=Work[j]+Allocation[i , j]; Finish[i] = True; 到第2)步。 4) 直到所有Finish[i]=True,表示系统处于安全状态;否则系统处于不安全状态。 5.8 实验设备 PC机1台,要求安装DOS7.1、Turbo C3.0、Windows2000。 5.9 实验成绩评定 实验成绩评定方式包含实验报告成绩、实验过程成绩两个部分,其中实验过程成绩占60%、实验报告成绩占40%,如果其中任何一个部分成绩不及格,则总成绩按不及格处理。 5.10 实验报告 按照实验目的、实验内容、实验要求、实验设备、测试等部分进行组织。 5.11 实验思考 1) 针对死锁有哪些可行方案? 2) 死锁解除的难点是什么?
### 银行家算法示例题目及解答 #### 示例场景描述 考虑一个系统中有五个进程 \( P_0 \),\( P_1 \),\( P_2 \),\( P_3 \),\( P_4 \) 和三种类型的资源 R1, R2, R3。当前系统的状态如下: | Process | Max | Allocation | Need | |---------|--------|------------|----------| | \( P_0 \)| 7 5 3 | 0 1 0 | 7 4 3 | | \( P_1 \)| 3 2 2 | 2 0 0 | 1 2 2 | | \( P_2 \)| 9 0 2 | 3 0 2 | 6 0 0 | | \( P_3 \)| 2 2 2 | 2 1 1 | 0 1 1 | | \( P_4 \)| 4 3 3 | 0 0 2 | 4 3 1 | 当前可用的资源数量为 Available = (3, 3, 2). #### 安全序列检测过程 为了判断该状态下是否存在安全序列,按照银行家算法进行安全性检查。 1. 初始化工作列表 Work 设置为 Available 的初始值 (3, 3, 2). 2. 创建 Finish 数组用于记录每个进程的状态,默认全部设置为 false. 3. 寻找满足条件 `Need[i] <= Work` 并且尚未完成 (`Finish[i]=false`) 的进程 i. 对于上述表格中的数据: - **第一次迭代** - 检查所有进程需求是否小于等于 Work 值。 - 发现 \( P_1 \)'s Need(1, 2, 2) 小于等于 Work(3, 3, 2)[^2]. - 更新 Work += Allocation of \( P_1 \)=Work+(2, 0, 0)=(5, 3, 2). - 标记 \( P_1 \) 已经完成(Finish\[1\]=true). - **第二次迭代** - 继续寻找符合条件的新进程... - 找到 \( P_3 \)'s Need(0, 1, 1)<=Work(5, 3, 2). - 更新 Work+=Allocation of \( P_3 \)=Work+(2, 1, 1)=(7, 4, 3). - 标记 \( P_3 \) 已经完成(Finish\[3\]=true). 重复此操作直到找到完整的安全序列或者无法再找到任何可运行的进程为止。最终得到的安全序列为 `<P1,P3,...>` (具体取决于后续几步的结果)。如果能够成功构建这样一个序列,则说明此时处于安全状态;反之则表示存在潜在死锁风险[^4]. ```python def banker_algorithm(max_resources, allocated_resources, available_resources): need_matrix = [[max_res - alloc for max_res, alloc in zip(max_row, alloc_row)] for max_row, alloc_row in zip(max_resources, allocated_resources)] n_processes = len(max_resources) finish = [False] * n_processes work = list(available_resources) safe_sequence = [] while False in finish: found = False for i in range(n_processes): if not finish[i] and all([need <= w for need, w in zip(need_matrix[i], work)]): work = [w + a for w, a in zip(work, allocated_resources[i])] finish[i] = True safe_sequence.append(f"P{i}") found = True if not found: break return "Safe Sequence:" + ", ".join(safe_sequence) if all(finish) else "No Safe Sequence Found" # Example usage with given data points print(banker_algorithm( [(7, 5, 3), (3, 2, 2), (9, 0, 2), (2, 2, 2), (4, 3, 3)], [(0, 1, 0), (2, 0, 0), (3, 0, 2), (2, 1, 1), (0, 0, 2)], (3, 3, 2))) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值