这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战
最近小编在学习自考操作系统的过程中,了解到了一种可以避免进程死锁的算法-----银行家算法
如果您已经知道什么是银行家算法,只想看代码,直接到 源码部分
什么是银行家算法
银行家算法是操作系统中避免死锁的一种算法
什么是死锁
和我们线程死锁类似,不同线程持有对方的锁,多个线程又不能释放锁,即产生死锁
类似上图,P1 申请 输出设备,但是输出设备被P2占有,P2又申请输入设备 输入设备又被P1占有形成回路
如何避免呢?
和简单只要在资源分配前检测当前系统是否处于安全状态,是否能被分配,分配之后系统是否还是安全的
算法核心
举例说明: 假定某系统有三类资源A、B、C, A类资源共有10个资源实例, B类资源共有5个资源实例, C类资源共有7个资源实例, 现有5个进程P1、P2、P3、P4、P5, 它们对各类资源 的最大需求量和第-~次分配后已占有的资源量如图所示。
此时我们需要找可以直接满足分配的进程,可以看到 P2 进程直接可以满足,当P2 满足后,P2持有的资源全部释放,系统资源如图所示。
然后是P4,同理分配之后是
然后是P5,同理分配之后是
P1
直到最后是P3
所以安全序列就是:P2、P4、P5、P1、P3
源码
#include <iostream>
#include <string>
#include<random>
using namespace std;
//后缀标记Test为测试值
const int ResMaxSize = 20;//允许最大资源数
const int ProMaxSize = 10;//允许最大进程数
string ResName[ResMaxSize]; //资源名
string ResNameTest[4] = { "R1","R2","R3","R4" }; //测试数据
int Max[ProMaxSize][ResMaxSize]; //每一个进程对各种资源的最大需求
int MaxTest[ProMaxSize][ResMaxSize] = { {0,0,1,2},{2,7,5,0},{6,6,5,6},{4,3,5,6},{0,6,5,2} }; //测试数据
int Allocation[ProMaxSize][ResMaxSize]; //系统中每个进程已获得每种资源的资源数
int AllocationTest[ProMaxSize][ResMaxSize] = { {0,0,1,2},{2,0,0,0},{0,0,3,4},{2,3,5,4},{0,3,3,2} }; //测试数据
int Available[ResMaxSize]; //系统仍然可利用的各类资源数目
int AvailableTest[ResMaxSize] = { 2,1,0,0 }; //测试数据
int Need[ProMaxSize][ResMaxSize]; //每一个进程尚需的各类资源数
int Security[ProMaxSize]; //进程安全序列,也可以使用STL队列
int SNum = 0;
// 进程完成队列
bool ProFinish[ProMaxSize];
int ProNum; //实际进程数
int ProNumTest = 5; //测试数据
int ResNum; //实际资源数
int ResNumTest = 4; //测试数据
//需要完成的工作
void BankerInit();//初始设置:输入函数
void PrintSecurity();//输出安全序列
void OutPut();//输出函数
bool CheckRequest(int Pid, const int Request[]);//银行家算法核心,判断请求算法
bool CheckSafe();//安全性检查算法
bool TryCheckSafe();//安全性检查算法
void InitPost();
class Utils{
public:
static vector<string> split(const string &s, const string &seperator);
static int splitVar(const string &s, string delim,int param[] = {});
static bool allisNum(string str);
};
vector<string> Utils::split(const string &s, const string &seperator){
vector<string> result;
typedef string::size_type string_size;
string_size i = 0;
while(i != s.size()){
//找到字符串中首个不等于分隔符的字母;
int flag = 0;
while(i != s.size() && flag == 0){
flag = 1;
for(string_size x = 0; x < seperator.size(); ++x)
if(s[i] == seperator[x]){
++i;
flag = 0;
break;
}
}
//找到又一个分隔符,将两个分隔符之间的字符串取出;
flag = 0;
string_size j = i;
while(j != s.size() && flag == 0){
for(string_size x = 0; x < seperator.size(); ++x)
if(s[j] == seperator[x]){
flag = 1;
break;
}
if(flag == 0)
++j;
}
if(i != j){
result.push_back(s.substr(i, j-i));
i = j;
}
}
return result;
}
int Utils::splitVar(const string &s, string delim, int param[]) {
vector<string> input;
input = Utils::split(s, delim);
for (int i = 0; i < input.size(); i++) {
param[i] = atoi(input[i].c_str());
}
return input.size();
}
bool Utils::allisNum(string str)
{
for (int i = 0; i < str.size(); i++)
{
int tmp = (int)str[i];
if (tmp >= 48 && tmp <= 57)
{
continue;
}
else
{
return false;
}
}
return true;
}
//输入函数实现
void BankerInit()
{//可以直接在这里把各项值设置好
ProNum = ProNumTest; //设置实际处理进程数
ResNum = ResNumTest; //设置实际处理资源数
for (int i = 0; i < ResNum; i++)//设置资源名称
ResName[i] = ResNameTest[i];
//设置各进程对各资源的最大需求量
for (int i = 0; i < ProNum; i++)
for (int j = 0; j < ResNum; j++)
Max[i][j] = MaxTest[i][j];
//设置各进程对各资源的已获得数量
for (int i = 0; i < ProNum; i++)
for (int j = 0; j < ResNum; j++)
Allocation[i][j] = AllocationTest[i][j];
//设置系统各项资源的剩余可用数量
for (int i = 0; i < ResNum; i++)
Available[i] = AvailableTest[i];
//计算各进程还需要的资源数:Need数组
for (int i = 0; i < ProNum; i++)
for (int j = 0; j < ResNum; j++)
Need[i][j] = Max[i][j] - Allocation[i][j];
}
//输出安全序列
void PrintSecurity()
{
//……
cout << "-------------安全序列-------------" << endl;
for (int i = 0; i < SNum; ++i) {
cout << Security[i] << "\t";
}
cout << endl;
}
//输出函数
void OutPut()
{
cout << "============================================" << endl;
cout << "当前进程数:" << ProNum << ";当前资源种类数量:" << ResNum << endl;
for (int i = 0; i < ResNum; i++)
cout << "资源" << ResName[i] << "可用数量为: " << Available[i] << endl;
cout << "-------------------------------------------" << endl;
for (int i = 0; i < ProNum; i++)
{
cout << "进程" << i << "\t" <<(ProFinish[i] ? "完成" : "未完成") << endl;
for (int j = 0; j < ResNum; j++)
cout << "资源" << ResName[j] << "最大需求数量为: " << Max[i][j] << " 当前分配数量为: " << Allocation[i][j] << " 剩余需求数量为: " << Need[i][j] << endl;
}
cout << "============================================" << endl;
}
//银行家算法核心,判断请求算法
bool CheckRequest(int Pid,const int Request[])
{
//检查资源请求是否合理
for (int i = 0; i < ResNum; i++)
{
if (Request[i] > Need[Pid][i])//需求资源数已经超过系统可用最大值
{
//……
cout << "资源:" << ResName[i] << "需求数已经超过系统可用最大值" << endl;
return false;
}
if (Request[i] > Available[i])//尚无足够资源
{
cout << "资源:" << ResName[i] << "尚无足够资源" << endl;
return false;
}
}
// 分配失败之后数据回滚点
int AllocationTemp[ProNum][ResNum];
int NeedTemp[ProNum][ResNum];
int AvailableTemp[ResNum];
int SecurityTemp[ProNum];
bool ProFinishTemp[ProNum];
for (int i = 0; i < ProNum; ++i) {
for (int j = 0; j < ResNum; ++j) {
AllocationTemp[i][j] = Allocation[i][j];
NeedTemp[i][j] = Need[i][j];
}
SecurityTemp[i] = Security[i];
ProFinishTemp[i] = ProFinish[i];
AvailableTemp[i] = Available[i];
}
//尝试分配资源给进程,看看此次分配后系统是否处于安全状态
for (int i = 0; i < ResNum; i++)
{
//……
Allocation[Pid][i] += Request[i];
Available[i] -= Request[i];
Need[Pid][i] = Max[Pid][i] - Allocation[Pid][i];
}
// 分配成功之后数据回滚点
int AllocationSuccessTemp[ProNum][ResNum];
int NeedSuccessTemp[ProNum][ResNum];
bool ProFinishSuccessTemp[ProNum];
for (int i = 0; i < ProNum; ++i) {
for (int j = 0; j < ResNum; ++j) {
AllocationSuccessTemp[i][j] = Allocation[i][j];
NeedSuccessTemp[i][j] = Need[i][j];
}
ProFinishSuccessTemp[i] = ProFinish[i];
}
InitPost();
// OutPut();
if (TryCheckSafe())//检查分配后系统是否安全
{
//分配后系统安全,正式分配
cout << "本次资源分配给进程" << Pid << ",分配成功!" << endl;
for (int i = 0; i < ProNum; ++i) {
for (int j = 0; j < ResNum; ++j) {
if (Pid == i) {
Allocation[Pid][j] = 0;
} else{
Allocation[i][j] = AllocationSuccessTemp[i][j];
}
Need[i][j] = NeedSuccessTemp[i][j];
}
if (Pid == i) {
ProFinish[Pid] = true;
} else{
ProFinish[i] = ProFinishSuccessTemp[i];
}
}
OutPut();
return true;
}
else {//分配后不安全,分配失效,资源恢复
cout << "本次资源分配后系统不安全,分配作废" << std::endl;
// 资源恢复
for (int i = 0; i < ProNum; ++i) {
for (int j = 0; j < ResNum; ++j) {
Allocation[i][j] = AllocationTemp[i][j];
Need[i][j] = NeedTemp[i][j];
}
Security[i] = SecurityTemp[i];
ProFinish[i] = ProFinishTemp[i];
Available[i] = AvailableTemp[i];
}
OutPut();
return false;
}
}
bool CheckSafe(){
//数据备份
int AllocationTemp[ProNum][ResNum];
int NeedTemp[ProNum][ResNum];
bool ProFinishTemp[ProNum];
for (int i = 0; i < ProNum; ++i) {
for (int j = 0; j < ResNum; ++j) {
AllocationTemp[i][j] = Allocation[i][j];
NeedTemp[i][j] = Need[i][j];
}
ProFinishTemp[i] = ProFinish[i];
}
bool b= TryCheckSafe();
// 资源恢复
for (int i = 0; i < ProNum; ++i) {
for (int j = 0; j < ResNum; ++j) {
Allocation[i][j] = AllocationTemp[i][j];
Need[i][j] = NeedTemp[i][j];
}
ProFinish[i] = ProFinishTemp[i];
}
return b;
}
void InitPost(){
for (int i = 0; i < ProNum; ++i) {
int j;
for (j = 0; j < ResNum; ++j) {
if (Need[i][j] != 0) {
break;
}
}
if (j == ResNum) {
// 已经分配完毕,需要释放资源
cout << "进程:" << i << "\t" << "已经分配完毕" << endl;
for (j = 0; j < ResNum; ++j) {
Available[j] += Allocation[i][j];
Allocation[i][j] = 0;
}
ProFinish[i] = true;
}
}
}
//安全性算法
bool TryCheckSafe()
{
int Work[ResNum];//表示系统可提供给进程继续运行所需的各类资源数目
//初始化Work 和 Finish 数组
for (int i = 0; i < ResNum; i++) {
Work[i] = Available[i];
}
SNum = 0;//重置安全序列队列
cout << "TryCheckSafe" << endl;
while (true)
{
int i;
//检查是否全部都处于安全状态
for (i = 0; i < ProNum; i++)
if (!ProFinish[i]) break;
//如果全都处于安全状态,则说明此时系统也处于安全状态
if (i == ProNum)
{
// cout << "系统此时安全!" << endl;
return true;
}
//i<ProNum 不是所有的进程都在安全状态
for (i = 0; i < ProNum; i++)
{
if (!ProFinish[i])//如果当前这个进程没有执行完
{
//尝试给这个进程分配资源并检查资源是否都足够
int j;
for (j = 0; j < ResNum; ++j) {
if (Need[i][j] > Work[j]) {
break;
}
}
bool flag = j == ResNum;
if (flag)//i进程需要的资源完全够分配
{
cout << "执行进程" << i << " ,系统可利用资源更新" << endl;
//将该进程加入安全序列中
Security[SNum] = i;
SNum++;
//调用进程运行,并且释放进程所占资源,输出可用资源的更新情况
for (int k = 0; k < ResNum; ++k) {
Need[i][k] = 0;
Work[k] += Allocation[i][k];
Allocation[i][k] = 0;
ProFinish[i] = true;
}
// cout << "调用完后进入下一轮查找安全进程" << endl;
// OutPut();
// cout << "==================" << endl;
break; //调用完后进入下一轮查找安全进程
}
}
}
//如果进程全部遍历完也没有任何一个执行,则说明此时无法分配,不安全
if (i == ProNum)
{
// cout << "系统此时不安全!" << endl;
return false;
}
}
}
//=============================主函数=======================
int main()
{
int choice = 0;
BankerInit();//银行家算法初始化
InitPost();
while (true)
{
cout << "================银行家算法================" << endl;
cout << "------------1.判断当前系统状态------------" << endl;
cout << "------------2.申请资源--------------------" << endl;
cout << "------------3.输出资源--------------------" << endl;
cout << "------------9.退出------------------------" << endl;
cout << "==========================================" << endl;
string inputVar;
cin >> inputVar;
bool isNum = Utils::allisNum(inputVar);
if (!isNum) {
cout << "输入有误" << endl;
continue;
}
choice = atoi(inputVar.c_str());
switch (choice) {
case 1:
{
if (CheckSafe())
{
cout << "系统此时安全!" << endl;
PrintSecurity();
}
else
{
cout << "系统此时不安全!" << endl;
}
break;
}
case 2:
{
int Pid;
int Request[ResNum];
cout << "请输入发起请求的进程号:" << endl;
cin >> Pid; //测试数据:2
if (Pid > ProNum) {
cout << "进程编号有误:" << endl;
break;
}
string dataVar;
cout << "请输入请求的资源的数量:" << endl;
cin >> dataVar;
Utils::splitVar(dataVar, ",", Request);
bool flag = true;
for (int i = 0; i < ResNum && flag; i++) //测试数据:0 1 0 0
{
if (Need[Pid][i] < Request[i]) {
cout << ResName[i] << "=> 超出最大资源数量:" << Request[i] << endl;
flag = false;
continue;
}
if (Available[i] < Request[i]) {
cout << ResName[i] << "=> 超出可用资源数量:" << Request[i] << endl;
flag = false;
continue;
}
}
if (!flag) {
break;
}
cout << "申请资源如下:";
for (int i = 0; i < ResNum; i++) //测试数据:0 1 0 0
{
cout << Request[i] << "\t";
}
cout << endl;
if (CheckRequest(Pid, Request))
{
cout << "资源分配成功, 系统此时安全!" << endl;
PrintSecurity();
}
else
{
cout << "资源分配失败,系统此时不安全!" << endl;
}
break;
}
case 3:
OutPut();
break;
case 9:
return 0;//结束程序
default:
cout << "请输入正确选项" << endl;
continue;
}
}
return 0;
}