操作系统银行家算法在C++中的实现
银行家算法简介
死锁会引起计算机工作僵死,因此操作系统中必须防止。本代码的目的在于编写和调试一个系统动态分配资源的简单模拟程序。
代码实现
头文件及宏定义
#include<iostream>
#include<map>
#include<time.h>
using namespace std;
#define random(x) rand()%(x)
经过对银行家算法需要存放的数据的分析,我们可以发现对于每一种资源和进程他们的一一对应性很强,所以我选择使用map容器对资源和分配情况进行存储。 另外我们需要用到随机数给进程随机出已分配的资源和需要的总资源,所以添加宏定义,方便后续代码随机数的使用,也提高代码的可读性。同时需要插入头文件time.h作为随机数种子,让随机数真正随机。
准备模块
srand(time(NULL));//随机数种子,只需执行一次
cout << "***************************************" << endl;
cout << "欢迎使用本程序~" << endl;
cout << "请输入进程数n(建议4~5个):" << endl;
int n;
cin >> n;
cout << "***************************************" << endl;
由于银行家算法的输出数据量很大,数据种类很多,为了代码的美观性,我用连续的*字符将每个模块分割。提示用户输入进程数,建议的4~5个进程取决于后续定义的每个进程需要分配的资源以及总资源量,由于我后面设置的随机数范围,进程数为4时系统处于安全状态,而为5时处于死锁、不安全状态,所以推荐输入4或5的进程可以全方位检测本代码的正确性。(建议的数字要根据后续的运行试出来,并不是一开始就能写出来的,建议还是取两个临界,一个安全,一个死锁) 另外,输出语句
cout << "请输入进程数n(建议4~5个):" << endl;
一定要写在
cin >> n;
的前面,否则会出现用户界面要先输入才能出现提示的情况。
资源分配模块
multimap<int, int>resourse;
for (int m = 1; m <= 4; m++)
{
resourse.insert(pair<int, int>(m, (random(14 - 10 + 1)) + 10));
}
for (auto resour = resourse.begin(); resour != resourse.end(); resour++)
cout << "系统中资源" << resour->first << "的总量为" << resour->second << endl;
multimap<int, int>allocation1;
for (int i = 1; i <= n; i++)
{
allocation1.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源1:" << endl;
for (auto allocate1 = allocation1.begin(); allocate1 != allocation1.end(); allocate1++)
cout << "进程编号为" << allocate1->first << "的进程已分配" << allocate1->second << endl;
multimap<int, int>allocation2;
for (int i = 1; i <= n; i++)
{
allocation2.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源2:" << endl;
for (auto allocate2 = allocation2.begin(); allocate2 != allocation2.end(); allocate2++)
cout << "进程编号为" << allocate2->first << "的进程已分配" << allocate2->second << endl;
multimap<int, int>allocation3;
for (int i = 1; i <= n; i++)
{
allocation3.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源3:" << endl;
for (auto allocate3 = allocation3.begin(); allocate3 != allocation3.end(); allocate3++)
cout << "进程编号为" << allocate3->first << "的进程已分配" << allocate3->second << endl;
multimap<int, int>allocation4;
for (int i = 1; i <= n; i++)
{
allocation4.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源4:" << endl;
for (auto allocate4 = allocation4.begin(); allocate4 != allocation4.end(); allocate4++)
cout << "进程编号为" << allocate4->first << "的进程已分配" << allocate4->second << endl;
multimap<int, int>need1;
for (int i = 1; i <= n; i++)
{
need1.insert(pair<int, int>(i, random(5 - allocation1.find(i)->second + 1) + allocation1.find(i)->second));
}
cout << "***************************************" << endl;
cout << "对于系统中资源1:" << endl;
for (auto nee1 = need1.begin(); nee1 != need1.end(); nee1++)
cout << "进程编号为" << nee1->first << "的进程还需要" << nee1->second << endl;
cout << "***************************************" << endl;
multimap<int, int>need2;
for (int i = 1; i <= n; i++)
{
need2.insert(pair<int, int>(i, random(5 - allocation2.find(i)->second + 1) + allocation2.find(i)->second));
}
cout << "对于系统中资源2:" << endl;
for (auto nee2 = need2.begin(); nee2 != need2.end(); nee2++)
cout << "进程编号为" << nee2->first << "的进程还需要" << nee2->second << endl;
cout << "***************************************" << endl;
multimap<int, int>need3;
for (int i = 1; i <= n; i++)
{
need3.insert(pair<int, int>(i, random(5 - allocation3.find(i)->second + 1) + allocation3.find(i)->second));
}
cout << "对于系统中资源3:" << endl;
for (auto nee3 = need3.begin(); nee3 != need3.end(); nee3++)
cout << "进程编号为" << nee3->first << "的进程还需要" << nee3->second << endl;
cout << "***************************************" << endl;
multimap<int, int>need4;
for (int i = 1; i <= n; i++)
{
need4.insert(pair<int, int>(i, random(5 - allocation4.find(i)->second + 1) + allocation4.find(i)->second));
}
cout << "对于系统中资源4:" << endl;
for (auto nee4 = need4.begin(); nee4 != need4.end(); nee4++)
cout << "进程编号为" << nee4->first << "的进程还需要" << nee4->second << endl;
cout << "***************************************" << endl;
这一个模块其实就是在做一件事情:对资源的分配以及将它们显示给用户。
我定义了名为resource的map用于存放系统总资源,并且用一个循环来控制资源种类的数量,这里我设置为4,即资源1、资源2、资源3、资源4,所以这里的循环用的是1到4。
名为allocation1 ~ 4的map分别存放对于资源1、2、3、4来说,已分配给每个进程的资源数量,所以这里的循环用的是1到n。
名为need1 ~ 4的map分贝存放对于资源1、2、3、4来说,每个进程还需要的资源数量,自然这里的循环用的也是1到n。
对于这里的随机数生成:对于allocation来说,我将随机数都设置为1到3:==random(2) + 1==,而对于need的随机数则复杂一些,是相应进程的相应资源的allocation的随机数的值到5:==random(5 - allocation4.find(i)->second + 1) + allocation4.find(i)->second)==。
这么设计原因是为了能使代码的所有功能都能显现出来,首先如此设计可以造成一个情况,就是对于一个进程,已分配很多的情况下,还需要的资源也相较于其他的进程会多一些,这样的好处就是不会出现系统很容易实现已分配资源多的进程,从而非常简单就释放出了很多资源,然后可以在接下来非常容易运行所有进程,即系统资源太多,这样就失去了银行家算法的意义,所以我这么定义以后,就能对应n的不同数值出现不同的情况,让代码完整地发挥了作用。
进程数n | 进程运行情况 |
---|---|
3 | 系统安全,没有进程进入等待,一次循环就全部完成 |
4 | 系统安全,有进程进入等待,经过两次循环全部完成 |
5 | 系统不安全,所有进程进入等待,系统死锁 |
剩余可分配模块
int totalallocate1 = 0;
for (auto allocate1 = allocation1.begin(); allocate1 != allocation1.end(); allocate1++)
{
totalallocate1 += allocate1->second;
}
int totalallocate2 = 0;
for (auto allocate2 = allocation2.begin(); allocate2 != allocation2.end(); allocate2++)
{
totalallocate2 += allocate2->second;
}
int totalallocate3 = 0;
for (auto allocate3 = allocation3.begin(); allocate3 != allocation3.end(); allocate3++)
{
totalallocate3 += allocate3->second;
}
int totalallocate4 = 0;
for (auto allocate4 = allocation4.begin(); allocate4 != allocation4.end(); allocate4++)
{
totalallocate4 += allocate4->second;
}
multimap<int, int>availble;
availble.insert(pair<int, int>(1, resourse.find(1)->second - totalallocate1));
availble.insert(pair<int, int>(2, resourse.find(2)->second - totalallocate2));
availble.insert(pair<int, int>(3, resourse.find(3)->second - totalallocate3));
availble.insert(pair<int, int>(4, resourse.find(4)->second - totalallocate4));
for (auto avail = availble.begin(); avail != availble.end(); avail++)
cout << "系统中资源" << avail->first << "的可用量为" << avail->second << endl;
cout << "***************************************" << endl;
这个模块对前面每种已分配的资源进行总量计算,然后计算出剩余的资源,存放在名为available的map中。
运行模块
map<int, int>list;
for (int i = 1; i <= n; i++)
{
list.insert(pair<int, int>(i, i));
}
int count = 0;
while (list.empty() == false)
{
int remem = count;
for (int i = 1; i <= n; i++)
{
if (list.find(i) != list.end())
{
if (availble.find(1)->second >= need1.find(i)->second &&
availble.find(2)->second >= need2.find(i)->second &&
availble.find(3)->second >= need3.find(i)->second &&
availble.find(4)->second >= need4.find(i)->second)
{
cout << "经系统判断,系统资源足够满足进程" << i << "的需求" << endl;
cout << "进程" << i << "完成,释放出全部资源" << endl;
availble.find(1)->second += allocation1.find(i)->second;
availble.find(2)->second += allocation2.find(i)->second;
availble.find(3)->second += allocation3.find(i)->second;
availble.find(4)->second += allocation4.find(i)->second;
list.erase(i);
count++;
for (auto avail = availble.begin(); avail != availble.end(); avail++)
cout << "当前系统中资源" << avail->first << "的可用量为" << avail->second << endl;
cout << "***************************************" << endl;
}
else
{
cout << "经系统判断,系统资源不足以满足进程" << i << "的需求" << endl;
cout << "进程" << i << "无法运行,进入等待状态" << endl;
cout << "***************************************" << endl;
}
}
}
if (remem == count)
{
break;
}
}
if (list.empty() == true)
cout << "所有进程执行完毕,该系统处于安全状态" << endl;
else
cout << "有进程无法执行,系统死锁,该系统处于不安全状态" << endl;
cout << "感谢您的使用~祝您生活愉快!" << endl;
cout << "***************************************" << endl;
在运行模块中,我定义了名为list的map用于存放所有进程,相当于将进程按编号拉成一个就绪队列,逐个判断是否可以运行。
每运行成功一个进程,就释放出它所有的资源,并且将它从list中删除。
所以最外层的while循环控制条件就是list不为空,只要不为空则继续里面的for循环。
内层for循环是从进程编号1判断到n,逐个判断是否系统所拥有的每种资源均满足该进程,如果均满足,则给该进程运行,并释放所有资源,只要有一种资源不满足就将其进入等待状态,继续判断下一个进程。
这里可以看到我在循环之前就定义了一个count变量,这个变量的作用非常重要,他是用于计算在每个大循环中有几个进程成功运行了,所以在每个进程成功运行时count++,另外我定义了remem变量在每个大循环的开始记录循环开始时count的数值,如果循环结束后count依然等于remem,说明当次大循环没有任何进程成功运行了,如果继续用while循环来判断则会形成死循环,所以我们用
if (remem == count)
{
break;
}
这个语句来控制循环的结束,即一旦一个循环中没有任何进程能成功运行,则跳出循环,并提示用户系统死锁,处于不安全状态。
跑的结果我放在下面:
完整代码
#include<iostream>
#include<map>
#include<time.h>
using namespace std;
#define random(x) rand()%(x)
int main()
{
srand(time(NULL));//随机数种子,只需执行一次
cout << "***************************************" << endl;
cout << "欢迎使用本程序~" << endl;
cout << "请输入进程数n(建议4~5个):" << endl;
int n;
cin >> n;
cout << "***************************************" << endl;
multimap<int, int>resourse;
for (int m = 1; m <= 4; m++)
{
resourse.insert(pair<int, int>(m, (random(14 - 10 + 1)) + 10));
}
for (auto resour = resourse.begin(); resour != resourse.end(); resour++)
cout << "系统中资源" << resour->first << "的总量为" << resour->second << endl;
multimap<int, int>allocation1;
for (int i = 1; i <= n; i++)
{
allocation1.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源1:" << endl;
for (auto allocate1 = allocation1.begin(); allocate1 != allocation1.end(); allocate1++)
cout << "进程编号为" << allocate1->first << "的进程已分配" << allocate1->second << endl;
multimap<int, int>allocation2;
for (int i = 1; i <= n; i++)
{
allocation2.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源2:" << endl;
for (auto allocate2 = allocation2.begin(); allocate2 != allocation2.end(); allocate2++)
cout << "进程编号为" << allocate2->first << "的进程已分配" << allocate2->second << endl;
multimap<int, int>allocation3;
for (int i = 1; i <= n; i++)
{
allocation3.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源3:" << endl;
for (auto allocate3 = allocation3.begin(); allocate3 != allocation3.end(); allocate3++)
cout << "进程编号为" << allocate3->first << "的进程已分配" << allocate3->second << endl;
multimap<int, int>allocation4;
for (int i = 1; i <= n; i++)
{
allocation4.insert(pair<int, int>(i, random(2) + 1));
}
cout << "***************************************" << endl;
cout << "对于系统中资源4:" << endl;
for (auto allocate4 = allocation4.begin(); allocate4 != allocation4.end(); allocate4++)
cout << "进程编号为" << allocate4->first << "的进程已分配" << allocate4->second << endl;
multimap<int, int>need1;
for (int i = 1; i <= n; i++)
{
need1.insert(pair<int, int>(i, random(5 - allocation1.find(i)->second + 1) + allocation1.find(i)->second));
}
cout << "***************************************" << endl;
cout << "对于系统中资源1:" << endl;
for (auto nee1 = need1.begin(); nee1 != need1.end(); nee1++)
cout << "进程编号为" << nee1->first << "的进程还需要" << nee1->second << endl;
cout << "***************************************" << endl;
multimap<int, int>need2;
for (int i = 1; i <= n; i++)
{
need2.insert(pair<int, int>(i, random(5 - allocation2.find(i)->second + 1) + allocation2.find(i)->second));
}
cout << "对于系统中资源2:" << endl;
for (auto nee2 = need2.begin(); nee2 != need2.end(); nee2++)
cout << "进程编号为" << nee2->first << "的进程还需要" << nee2->second << endl;
cout << "***************************************" << endl;
multimap<int, int>need3;
for (int i = 1; i <= n; i++)
{
need3.insert(pair<int, int>(i, random(5 - allocation3.find(i)->second + 1) + allocation3.find(i)->second));
}
cout << "对于系统中资源3:" << endl;
for (auto nee3 = need3.begin(); nee3 != need3.end(); nee3++)
cout << "进程编号为" << nee3->first << "的进程还需要" << nee3->second << endl;
cout << "***************************************" << endl;
multimap<int, int>need4;
for (int i = 1; i <= n; i++)
{
need4.insert(pair<int, int>(i, random(5 - allocation4.find(i)->second + 1) + allocation4.find(i)->second));
}
cout << "对于系统中资源4:" << endl;
for (auto nee4 = need4.begin(); nee4 != need4.end(); nee4++)
cout << "进程编号为" << nee4->first << "的进程还需要" << nee4->second << endl;
cout << "***************************************" << endl;
int totalallocate1 = 0;
for (auto allocate1 = allocation1.begin(); allocate1 != allocation1.end(); allocate1++)
{
totalallocate1 += allocate1->second;
}
int totalallocate2 = 0;
for (auto allocate2 = allocation2.begin(); allocate2 != allocation2.end(); allocate2++)
{
totalallocate2 += allocate2->second;
}
int totalallocate3 = 0;
for (auto allocate3 = allocation3.begin(); allocate3 != allocation3.end(); allocate3++)
{
totalallocate3 += allocate3->second;
}
int totalallocate4 = 0;
for (auto allocate4 = allocation4.begin(); allocate4 != allocation4.end(); allocate4++)
{
totalallocate4 += allocate4->second;
}
multimap<int, int>availble;
availble.insert(pair<int, int>(1, resourse.find(1)->second - totalallocate1));
availble.insert(pair<int, int>(2, resourse.find(2)->second - totalallocate2));
availble.insert(pair<int, int>(3, resourse.find(3)->second - totalallocate3));
availble.insert(pair<int, int>(4, resourse.find(4)->second - totalallocate4));
for (auto avail = availble.begin(); avail != availble.end(); avail++)
cout << "系统中资源" << avail->first << "的可用量为" << avail->second << endl;
cout << "***************************************" << endl;
map<int, int>list;
for (int i = 1; i <= n; i++)
{
list.insert(pair<int, int>(i, i));
}
int count = 0;
while (list.empty() == false)
{
int remem = count;
for (int i = 1; i <= n; i++)
{
if (list.find(i) != list.end())
{
if (availble.find(1)->second >= need1.find(i)->second &&
availble.find(2)->second >= need2.find(i)->second &&
availble.find(3)->second >= need3.find(i)->second &&
availble.find(4)->second >= need4.find(i)->second)
{
cout << "经系统判断,系统资源足够满足进程" << i << "的需求" << endl;
cout << "进程" << i << "完成,释放出全部资源" << endl;
availble.find(1)->second += allocation1.find(i)->second;
availble.find(2)->second += allocation2.find(i)->second;
availble.find(3)->second += allocation3.find(i)->second;
availble.find(4)->second += allocation4.find(i)->second;
list.erase(i);
count++;
for (auto avail = availble.begin(); avail != availble.end(); avail++)
cout << "当前系统中资源" << avail->first << "的可用量为" << avail->second << endl;
cout << "***************************************" << endl;
}
else
{
cout << "经系统判断,系统资源不足以满足进程" << i << "的需求" << endl;
cout << "进程" << i << "无法运行,进入等待状态" << endl;
cout << "***************************************" << endl;
}
}
}
if (remem == count)
{
break;
}
}
if (list.empty() == true)
cout << "所有进程执行完毕,该系统处于安全状态" << endl;
else
cout << "有进程无法执行,系统死锁,该系统处于不安全状态" << endl;
cout << "感谢您的使用~祝您生活愉快!" << endl;
cout << "***************************************" << endl;
}
对于这个代码的讲解,我觉得做的不够细致,实际上也取决于这个代码的特殊性,包含大量数据的存储与变化,但是大量数据其实都只指向唯一的变量:资源,所以对于很长串的代码我的解释不多就是因为没什么可解释的,因为只是在做简单的数据存储和变化,如果难以看懂的话可以先看一下我的“这可能是你见过唯一一个无需排序的优先级进程调度”这一篇博客对于map容器的解释,以及可以先学习一下map容器的基本概念与用法,之后再来看这篇博客我对银行家算法的资源管理,就可以事半功倍啦。
总结
银行家算法实际上实现难度不大,不过数据种类繁琐,需要写代码时集中精神,否则一但调用了错误的数据可能会出现崩溃的现象,并且排查难度很大,因为即使调用了错误的数据,但在逻辑上依然是正确的(比如在计算need2时调用了一部分allocation3的数据)另外对于最后的如何判断在当前循环下是否所有资源全部无法执行的条件是不容易摸索的,一开始我使用了flag去记录失败的进程数,然后用n、n的阶乘、list.size()去限制,都出现了死循环、多次重复循环、少循环的情况,试了很多办法才想到最后这个,所以写代码实际上可能不一定总是能一下用到正确的办法,慢慢尝试总会成功~本篇文章作于2021.4.28。