前言
银行家算法,是我们OS课上的一个非常重要的知识点,感觉可以说是必考题了,但是考试嘛,考过了以后不用就会忘,每次都要重新复(yu)习一遍,又非常麻烦,正好前段时间有机会实现了一遍,赶紧总结下,避免以后又忘了。
正文
银行家算法简介
银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死结产生的演算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。
(来自wiki)
这里的重点是避免!!! 避免!!! 避免!!!
针对死锁这种坑爹的情况有预防和避免两种大的解决思路,之前总是傻傻分不清楚。这里我们还是通过一个生动的例子来解释吧。
女朋友:康康啊,预防感冒,冲杯板x根吧。
康康:好滴。
女朋友:康康啊,出门系上我给你织的围巾吧,避免感冒。
康康:好几。
感受到预防和避免的差异了嘛,预防就是提前做好准备,而避免则是在实际操作中小心翼翼。
回到死锁,预防死锁就是破坏死锁的四个必要条件之一,而避免死锁则是在进程运行过程中通过一些手段来避免死锁。
算法详解
其实银行家算法非常简单。
系统维护了一张所有进程的资源表。进程对每种资源的总共需求数,当前已分配的资源数,还需要的资源数。
假设系统初始状态为S0,在每次请求资源(并且这次请求合法)时,会假设为进程分配需要的资源,这时系统进入状态S1*,判断这个假设状态是否为安全的,如果是安全的,才会进行真正分配,系统进入S1状态;否则系统不会进行资源分配。
判断系统此时状态是否安全的算法也很简单。
就是假设所有进程能否按照某种顺序运行(这里的运行就是 请求资源->工作->释放资源 这个过程)。
如果存在这样一个进程运行序列,就是安全的。反之则不安全。
源码分析
数据结构
const int process_nums = 5; // 进程数
const int resource_nums = 3; //资源种类数
//进程的两种状态
enum {
RUNNING = 0,
SLEEP
};
//模拟的进程 只有pid和state两个成员,默认为SLEEP状态
struct Process
{
Process(int id):pid(id), state(SLEEP){}
int pid;
int state;
};
vector<int> available; //一维数组,记录每种资源的现有(空闲)个数
vector<vector<int>> max_request, allocation, need,request;
//max_request 每个进程对每种资源的总共需求数 二维数组
//allocation 每个进程对每种资源的当前分配数 二维数组
//need 每个进程对每种资源的当前分配数(need[i][j] = max_request[i][j] - allocation[i][j]) 二维数组
vector<Process> process;
//进程组 每个进程的pid = index
模拟流程
while(isSomeProcessNeedResource(need)){
//模拟调度,让一个进程开始运行
now_running_process = scheProcess(need);
process[now_running_process].state = RUNNING;
//获取进程此次运行,对于每种资源的需求数
getRequest(now_running_process, request);
//判断此次需求是否合法
for(int i = 0; i < resource_nums; i++){
//此次需求大于need,说明需求错误
if(request[now_running_process][i] > need[now_running_process][i]){
cout << "request error" << endl;
return -1;
}
//此次需求大于available,资源数量不够,让进程阻塞 if(request[now_running_process][i] > available[i]){
process[now_running_process].state = SLEEP;
break;
}
}
//如果需求合法,进入分配阶段
if(process[now_running_process].state == RUNNING){
//(1)假设分配
for(int i = 0; i < resource_nums; i++){
available[i] -= request[now_running_process][i];
allocation[now_running_process][i] += request[now_running_process][i];
need[now_running_process][i] -= request[now_running_process][i];
}
print(available, max_request, need ,allocation);
//判断经过分配后,整个系统是否处于安全状态
if(judgeSecurity(available, need, process, allocation) == -1){
//系统不安全,将假设分配的资源还给OS
for(int i = 0; i < resource_nums; i++){
available[i] += request[now_running_process][i];
allocation[now_running_process][i] -= request[now_running_process][i];
need[now_running_process][i] += request[now_running_process][i];
}
cout << "now is not security" << endl;
} else{
cout << "now is security" << endl;
}
process[now_running_process].state = SLEEP;
}
}
核心算法:安全性检验
判断系统当前状态是否安全。
int judgeSecurity(const vector<int>& available,
const vector<vector<int>>& need,
const vector<Process>& process,
const vector<vector<int>> &allocation)
{
vector<int> work(available);//现有的每种资源空闲数
vector<bool> finish(process_nums, false);//标志数组,判断进程是否完成工作
vector<int> security_list;
int p_nums = process_nums;
//当需要资源的进程数不为0
while(p_nums){
int s = p_nums;
for(int i = 0; i < process_nums; i++){
//如果进程还没有完成所有工作,并且它需要的资源数小于现有的空闲资源数,则可以给它分配资源
if(finish[i] == false && judgeNeed(need[i], work)){
//分配之后则认为进程已经完成所有工作
finish[i] = true;
p_nums--;
security_list.push_back(i);
//将进程之前占有的资源释放
for(int j = 0; j < resource_nums; j++)
work[j] += allocation[i][j];
}
}
//如果没有进程能被分配给资源,说明会产生死锁,系统处于不安全状态
if(s == p_nums)
return -1;
}
//输出当前状态存在的安全序列
cout << "security_list is :"<< endl;
for(auto i : security_list)
cout << "p" << i << "->";
cout << "end" << endl;
return 0;
}