C++:银行家算法(附带源码)
·
项目名称:银行家算法实现
项目背景
银行家算法(Banker's Algorithm)是一种用于避免死锁的算法,主要用于资源分配系统中,确保系统在分配资源后仍然处于安全状态。该算法由艾兹赫尔·狄克斯特拉(Edsger Dijkstra)提出,最初用于银行贷款系统,因此得名“银行家算法”。
在操作系统中,资源分配和管理是核心问题,特别是在多进程并发执行的环境下,需要避免由于资源竞争引发的死锁。银行家算法通过对进程资源需求的动态分析,在分配资源前进行“安全性检查”,从而保证系统不会进入死锁状态。
项目目标
- 功能实现:
- 使用C++实现银行家算法,支持动态资源分配与释放。
- 代码注释与解读:
- 提供详细的注释与算法流程解读,便于学习与扩展。
- 项目结构:
- 模块化设计,包含资源初始化、分配、安全性检查等功能。
- 测试与验证:
- 设计多组测试用例,验证算法的正确性与鲁棒性。
银行家算法的基本原理
核心概念
- 资源类型: 系统中有多种类型的资源,例如CPU、内存、I/O设备等。
- 矩阵描述:
Available:系统当前可用资源数量向量。Max:每个进程对各类资源的最大需求矩阵。Allocation:当前已经分配给各进程的资源数量矩阵。Need:每个进程尚需的资源数量矩阵,Need[i][j] = Max[i][j] - Allocation[i][j]。
安全性检查
银行家算法在分配资源之前,通过“安全性算法”预测分配后的系统是否处于安全状态。系统安全状态的定义是:存在一个进程执行顺序,使得所有进程可以在有限时间内完成并释放资源。
资源分配流程
- 检查请求是否合法(请求量不能超过进程声明的最大需求)。
- 判断资源是否足够满足请求(请求量不能超过系统当前可用资源量)。
- 假设分配资源,检查分配后的系统是否安全:
- 如果安全,则实际分配资源。
- 如果不安全,拒绝分配,保持系统稳定。
项目结构
模块化设计如下:
- 主模块:程序入口,负责用户交互和调用核心函数。
- 数据初始化模块:定义资源矩阵,初始化进程信息。
- 资源分配模块:根据进程请求更新资源分配状态。
- 安全性检查模块:判断当前资源分配是否安全。
- 测试模块:包含不同场景下的测试用例。
C++实现
以下是银行家算法的完整实现代码:
#include <iostream>
#include <vector>
using namespace std;
// 定义全局变量
int numProcesses, numResources; // 进程数和资源种类数
vector<int> Available; // 当前可用资源
vector<vector<int>> Max; // 每个进程的最大需求
vector<vector<int>> Allocation; // 已分配资源
vector<vector<int>> Need; // 尚需资源
// 安全性检查函数
bool isSafe() {
vector<int> Work = Available; // 可用资源向量
vector<bool> Finish(numProcesses, false); // 记录进程是否完成
vector<int> safeSequence; // 安全序列
for (int count = 0; count < numProcesses; ++count) {
bool found = false;
for (int i = 0; i < numProcesses; ++i) {
if (!Finish[i]) {
bool canAllocate = true;
for (int j = 0; j < numResources; ++j) {
if (Need[i][j] > Work[j]) { // 当前资源不足
canAllocate = false;
break;
}
}
if (canAllocate) {
// 假设分配资源
for (int j = 0; j < numResources; ++j) {
Work[j] += Allocation[i][j];
}
safeSequence.push_back(i); // 记录进程顺序
Finish[i] = true; // 标记完成
found = true;
}
}
}
if (!found) { // 如果找不到可以分配的进程
cout << "系统处于不安全状态!" << endl;
return false;
}
}
cout << "系统处于安全状态,安全序列为:";
for (int i : safeSequence) {
cout << "P" << i << " ";
}
cout << endl;
return true;
}
// 资源请求函数
void requestResource(int processID, vector<int> request) {
cout << "进程 P" << processID << " 请求资源:";
for (int r : request) {
cout << r << " ";
}
cout << endl;
// 检查请求是否合法
for (int i = 0; i < numResources; ++i) {
if (request[i] > Need[processID][i]) {
cout << "请求超过进程的最大需求!" << endl;
return;
}
if (request[i] > Available[i]) {
cout << "请求超过系统当前可用资源!" << endl;
return;
}
}
// 假设分配资源
for (int i = 0; i < numResources; ++i) {
Available[i] -= request[i];
Allocation[processID][i] += request[i];
Need[processID][i] -= request[i];
}
// 安全性检查
if (isSafe()) {
cout << "资源分配成功!" << endl;
} else {
// 回滚资源分配
cout << "分配后系统处于不安全状态,拒绝分配!" << endl;
for (int i = 0; i < numResources; ++i) {
Available[i] += request[i];
Allocation[processID][i] -= request[i];
Need[processID][i] += request[i];
}
}
}
int main() {
// 输入系统资源信息
cout << "请输入进程数和资源种类数: ";
cin >> numProcesses >> numResources;
Available.resize(numResources);
Max.resize(numProcesses, vector<int>(numResources));
Allocation.resize(numProcesses, vector<int>(numResources, 0));
Need.resize(numProcesses, vector<int>(numResources));
cout << "请输入系统可用资源向量: ";
for (int i = 0; i < numResources; ++i) {
cin >> Available[i];
}
cout << "请输入每个进程的最大需求矩阵: " << endl;
for (int i = 0; i < numProcesses; ++i) {
for (int j = 0; j < numResources; ++j) {
cin >> Max[i][j];
Need[i][j] = Max[i][j]; // 初始化Need矩阵
}
}
// 模拟资源请求
while (true) {
int processID;
vector<int> request(numResources);
cout << "\n请输入请求资源的进程ID (-1退出): ";
cin >> processID;
if (processID == -1) break;
cout << "请输入请求资源向量: ";
for (int i = 0; i < numResources; ++i) {
cin >> request[i];
}
requestResource(processID, request);
}
return 0;
}
代码解读
-
数据结构:
- 使用二维向量存储
Max、Allocation和Need矩阵。 - 使用一维向量存储
Available和Work。
- 使用二维向量存储
-
核心逻辑:
- 安全性检查:逐进程模拟分配,确保系统最终处于安全状态。
- 资源请求处理:先验证请求的合法性,再尝试分配并检查安全性。
-
用户交互:
- 用户动态输入资源请求,系统实时判断是否可以分配。
测试用例
测试数据
- 系统可用资源:
[3, 3, 2] - 最大需求矩阵
P0: [7, 5, 3]
P1: [3, 2, 2]
P2: [9, 0, 2]
P3: [2, 2, 2]
P4: [4, 3, 3]
当前分配矩阵
P0: [0, 1, 0]
P1: [2, 0, 0]
P2: [3, 0, 2]
P3: [2, 1, 1]
P4: [0, 0, 2]
测试场景
- 合法请求:进程
P1请求资源[1, 0, 2]。 - 非法请求:进程
P2请求资源[6, 0, 2](超出可用资源)。
总结与优化方向
-
优点:
- 确保资源分配安全性,避免死锁。
- 易于理解和实现,适合小规模系统。
-
缺点:
- 时间复杂度较高,安全性检查需遍历所有进程。
- 适用场景有限,不适合高并发大规模资源管理。
-
优化方向:
- 引入多线程并行检查,提高安全性判断效率。
- 结合实际场景设计更灵活的资源分配策略(如优先级)。
更多推荐


所有评论(0)