解决死锁问题之银行家算法

银行家算法

背景:

银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。在这样的描述中,银行家就好比操作系统,资金就是资源,客户就相当于要申请资源的进程。

银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但银行家算法在系统在进行资源分配之前(并不是真的不分配,这样就没法做了,只不过是试探性分配,不满足的话再恢复),应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。要解释银行家算法,必须先解释操作系统安全状态和不安全状态。安全序列是指存在一个进程序列{P1,…,Pn}是安全的,不会死锁(至少两个线程占有某资源A,但是都不满足,剩余的资源A分配给谁仍然无法满足),安全状态如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态,安全状态一定是没有死锁发生;不安全状态不存在一个安全序列,不安全状态不一定导致死锁。

原理:

银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。每分配一次资源就测试一次是否安全,不是资源全部就位后才测试。我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
1、当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客(试探性分配)
2、顾客可以分期贷款,但贷款的总数不能超过最大需求量(可能一次并不能满足所需要的全部资源)
3、当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款(不存在死锁)
4、当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金(运行后释放)
操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能存在安全状态,则按当前的申请量分配资源,否则也要推迟分配。

设计

设计思路:

首先应输入算法实现过程中的各矩阵,接下来调用安全性算法来对当前系统状态进行检查,检查当前状态是否安全。若安全则可以进行资源请求;若不安全,则直接返回结束程序运行。如果安全,进程可以提出资源请求。提出请求之后,系统给与试分配。若试分配之后的系统状态调用安全性算法,检查为安全则可以给与正式分配。否则,拒绝当前进程的资源申请,回收试分配的资源。

银行家算法执行步骤

设Request i 是进程P i的请求向量,如果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);否则表示尚无足够资源,P i需等待。

(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) 系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程P i,以完成本次分配;否则,将本次的试分配作废,恢复原来的资源分配状态,让进程P i等待。

安全性算法执行步骤:

(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;

转步骤(2)执行

(4)如果所有进程的Finish[i]= true 都满足,则表示系统处于安全状态;否则,系统处于不安全状态。

主要数据结构:

(1)可利用资源向量Available[j]

(2)最大需求矩阵Max[i][j]

(3)分配矩阵 Allocation[i][j]

(4)需求矩阵 Need[i][j]

(5)资源申请矩阵 Request[j]

(6)工作向量 Work[j]

(7)标志向量 Finish[i]

具体实现:

#include
#include
using namespace std;
//ProcessNum: 表示进程个数
//ResourceNum: 表示资源种类个数
int  ProcessNum, ResourceNum;
//输入函数:进行矩阵的初始化
void  Init(vector<int>& Avaliable, vector<vector<int>>& Max, vector<vector<int>>& Allocation, vector<vector<int>>& Need, vector<int>SS);
//银行家算法
void BM(vector<int>& Avaliable, vector<vector<int>>& Allocation, vector<vector<int>>& Need, vector<int>& SS, vector<vector<int>>& Max);
//安全性算法
bool SM(vector<int>& Avaliable, vector<vector<int>>& Need, vector<vector<int>>& Allocation, vector<int>& SS);
//打印一维矩阵
void Print1(vector<int>& vec);
//打印二维矩阵
void Print2(vector<vector<int>>& vec);
//初始化矩阵
void  Init(vector<int>& Avaliable, vector<vector<int>>& Max, vector<vector<int>>& Allocation, vector<vector<int>>& Need, vector<int>SS)
{
 //对Avaliable矩阵进行初始化
 printf("请输入系统当前可提供的每一类资源的个数:\n");
 for (int i = 0; i < ResourceNum; ++i)
 {
  cin >> Avaliable[i];
 }
 //对Allocation矩阵进行初始化
 printf("请输入每一个进程已分配到每类资源的个数:\n");
 for (int i = 0; i < ProcessNum; ++i)
 {
  for (int j = 0; j < ResourceNum; ++j)
  {
   cin >> Allocation[i][j];
  }
 }
 //对Need矩阵进行初始化
 printf("请输入每一个进程仍需每类资源的个数:\n");
 for (int i = 0; i < ProcessNum; ++i)
 {
  for (int j = 0; j < ResourceNum; ++j)
  {
   cin >> Need[i][j];
  }
 }
 //Max矩阵:表示每一个进程对于每一类资源的最大需求
 //Max[i][j]=Allocation[i][j]+Need[i][j]
 for (int i = 0; i < ProcessNum; ++i)
 {
  for (int j = 0; j < ResourceNum; ++j)
  {
   Max[i][j] = Allocation[i][j] + Need[i][j];
  }
 }
}
//银行家算法
void BM(vector<int>& Avaliable, vector<vector<int>>& Allocation, vector<vector<int>>& Need, vector<int>& SS, vector<vector<int>>& Max)
{
 cout << "请输入请求分配资源的进程号:";
 int num = 0, n = 0;
 cin >> num;
 cout << "请输入所需各类资源的个数" << endl;
 //Request:存储进程i的请求资源序列
 vector<int>Request(ResourceNum, 0);
 for (int i = 0; i < ResourceNum; ++i)
 {
  cin >> Request[i];
 }
 n = num - 1;
 cout << "试分配前系统可提供的每一类资源的个数:" << endl;
 Print1(Avaliable);
 cout << "试分配前每一个进程已分配到每类资源的个数:" << endl;
 Print2(Allocation);
 cout << "试分配前每一个进程仍需每类资源的个数:" << endl;
 Print2(Need);
 for (int i = 0; i < ResourceNum; ++i)
 {
  //1.满足Request[i] <= Need[n][i]:转2
  if (Request[i] <= Need[n][i])
  {
   //2.满足Request[i] <= Avaliable[i]
   if (Request[i] <= Avaliable[i])
   {
    //试分配
    Need[n][i] = Need[n][i] - Request[i];
    Allocation[n][i] = Allocation[n][i] + Request[i];
    Avaliable[i] = Avaliable[i] - Request[i];
   }
   //不满足2.Request[i] <= Avaliable[i]:阻塞
   else
   {
    cout << "可用资源暂不能满足P" << n << "请求资源需要," << "P" << n << "阻塞等待" << endl;
    for (int j = 0; j < i; ++j)
    {
     Need[n][j] = Need[n][j] + Request[j];
     Allocation[n][j] = Allocation[n][j] - Request[j];
     Avaliable[j] = Avaliable[j] + Request[j];
    }
    int choose = 0;
    cout << "请选择功能:" << endl;
    cout << "1.退出" << endl;
    cout << "2.继续进行资源申请" << endl;
    cin >> choose;
    switch (choose)
    {
    case 1:
     cout << "您已经选择退出!" << endl;
     return;
    case 2:
     BM(Avaliable, Allocation, Need, SS, Max);
     break;
    }
   }
  }
  //不满足1.Request[i] <= Need[n][i]:出错
  else
  {
   cout << "错误:所请求资源大于自身所需资源!" << endl;
   for (int j = 0; j < i; ++j)
   {
	    Need[n][j] = Need[n][j] + Request[j];
	    Allocation[n][j] = Allocation[n][j] - Request[j];
	    Avaliable[j] = Avaliable[j] + Request[j];
	   }
   int choose = 0;
   cout << "请选择功能:" << endl;
   cout << "1.退出" << endl;
   cout << "2.继续进行资源申请" << endl;
   cin >> choose;
   switch (choose)
   {
   case 1:
    cout << "您已经选择退出!" << endl;
    return;
   case 2:
    BM(Avaliable, Allocation, Need, SS, Max);
    break;
   }
  }
 }
 cout << "试分配后系统可提供的每一类资源的个数:" << endl;
 Print1(Avaliable);
 cout << "试分配后每一个进程已分配到每类资源的个数:" << endl;
 Print2(Allocation);
 cout << "试分配后每一个进程仍需每类资源的个数:" << endl;
 Print2(Need);
 if (SM(Avaliable, Need, Allocation, SS))
 {
  cout << "该状态下是安全的,可以分配,该状态下的安全序列为:" << endl;
  for (int i = 0; i < ProcessNum; ++i)
  {
   cout << SS[i] << " ";
  }
  cout << endl;
  bool complete = true;
  for (int i = 0; i < ResourceNum; ++i)
  {
   if (0 != Need[n][i])
   {
    complete = false;
   }
  }
  if (complete)
  {
   for (int i = 0; i < ResourceNum; ++i)
   {
    Avaliable[i] += Allocation[n][i];
    Allocation[n][i] = 0;
   }
   cout << "当前系统可提供的每一类资源的个数:" << endl;
   Print1(Avaliable);
   cout << "每一个进程已分配到每类资源的个数:" << endl;
   Print2(Allocation);
   cout << "每一个进程仍需每类资源的个数:" << endl;
   Print2(Need);
  }
 }
 else
 {
  cout << "该状态下是不安全的,不能分配。" << endl;
  for (int i = 0; i < ResourceNum; ++i)
  {
   //状态不安全,归还资源
   Need[n][i] = Need[n][i] + Request[i];
   Allocation[n][i] = Allocation[n][i] - Request[i];
   Avaliable[i] = Avaliable[i] + Request[i];
  }
  cout << "系统当前可提供的每一类资源的个数:" << endl;
  Print1(Avaliable);
  cout << "每一个进程已分配到每类资源的个数:" << endl;
  Print2(Allocation);
  cout << "每一个进程仍需每类资源的个数:" << endl;
  Print2(Need);
 }
 int choose = 0;
 cout << "请选择功能:" << endl;
 cout << "1.退出" << endl;
 cout << "2.继续进行资源申请" << endl;
 cin >> choose;
 switch (choose)
 {
 case 1:
  cout << "您已经选择退出!" << endl;
  return;
 case 2:
  BM(Avaliable, Allocation, Need, SS, Max);
  break;
 }
}
//安全性算法
bool SM(vector<int>& Avaliable, vector<vector<int>>& Need, vector<vector<int>>& Allocation, vector<int>& SS)
{
 vector<int>Work = Avaliable;
 vector<char>Finish(ProcessNum, 'F');
 //Security sequence--->SS 安全序列
 int i = 0, j = 0, s = 0;
 while (i < ProcessNum)
 {
  if (Finish[i] == 'F')
  {
   //满足条件释放资源,并从头开始扫描进程集合
   while (j < ResourceNum && Need[i][j] <= Work[j])
   {
    j++;
   }
   //当j=ResourceNum,表示当前进程所需的每一个资源都满足当前系统可分配的资源
   if (j == ResourceNum)
   {
    //释放当前进程资源
    for (int k = 0; k < ResourceNum; k++)
    {
     Work[k] += Allocation[i][k];
    }
    Finish[i] = 'T'; //将其标志位置为T
    SS[s++] = i;  //保存安全序列
    i = -1; //将i置为-1,从头重新开始遍历
   }
  }
  j = 0;
  i++;
 }
 //遍历进程集合,如果有进程不满足,返回false
 for (int i = 0; i < ProcessNum; ++i)
 {
  if (Finish[i] == 'F')
  {
   return false;
  }
 }
 return true;     //如果进程都满足,返回true
}
//打印一维矩阵
void Print1(vector<int>& vec)
{
 for (int i = 0; i < ResourceNum; ++i)
 {
  cout << "    R" << i + 1;
 }
 cout << endl;
 for (int i = 0; i < ResourceNum; ++i)
 {
  cout << "     " << vec[i];
 }
 cout << endl;
}
//打印二维矩阵
void Print2(vector<vector<int>>& vec)
{
 for (int i = 0; i < ResourceNum; ++i)
 {
  cout << "    R" << i + 1;
 }
 cout << endl;
 for (int i = 0; i < ProcessNum; ++i)
 {
  cout << "P" << i;
  for (int j = 0; j < ResourceNum; ++j)
  {
   cout << "   " << vec[i][j] << "  ";
  }
  cout << endl;
 }
}
//测试函数
void test()
{
 cout << "**********银行家算法**********" << endl;
 printf("请输入进程个数以及资源种类数:");
 cin >> ProcessNum >> ResourceNum;
 vector<int>SS(ProcessNum, 0);//储存安全序列
 vector<int>Avaliable(ResourceNum, 0);//Avaliable:表示某类资源的可用数目
 vector<vector<int>>Max(ProcessNum, vector<int>(ResourceNum, 0));//表示某进程对于某资源的最大需求
 vector<vector<int>>Allocation(ProcessNum, vector<int>(ResourceNum, 0));//表示某进程已分配某资源的个数
 vector<vector<int>>Need(ProcessNum, vector<int>(ResourceNum, 0));//表示某进程尚需某资源的个数
 Init(Avaliable, Max, Allocation, Need, SS);//初始化函数
 if (SM(Avaliable, Need, Allocation, SS))//是安全状态
 {
  cout << "该状态下是安全的,可以分配,该状态下的安全序列为:" << endl;
  for (int i = 0; i < ProcessNum; ++i)
  {
   cout << SS[i] << " ";
  }
  cout << endl;
  //调用银行家算法
  BM(Avaliable, Allocation, Need, SS, Max);
 }
 else//不是安全状态
 {
  cout << "该状态下是不安全的,不能分配。" << endl;
  return;
 }
}
int main()
{
 test();
 return 0;
}

你可能感兴趣的:(解决死锁问题之银行家算法)