银行家算法

什么是银行家算法

银行家算法顾名思义就是模拟银行的借贷业务的一种算法,操作系统就相当于一个银行家,而进程就是客户,进程向操作系统请求资源、归还资源就相当于客户向银行借贷、还贷。这个应该是很好理解的。

理解这个名词之后,下面我们看看具体深入一点,银行家能否给一名客户贷款的要求是什么呢?很简单:在它还款期间,整个银行要能进行正常的资金周转。如果可以,那好,就借款给它,如果不能就不借给他。恩,就这么干脆。

换做操作系统的资源分配,也是如此:操作系统能否响应一个进程的资源请求,要求是,在它归还分配的资源之前,系统能维持一个正常的资源周转。到底什么是正常的周转?你可能在想。正常的周转就是,系统现有的资源能够满足多个进程的需求。也就是系统处于一个安全的状态。

银行家算法的数据结构

上面的论述,对银行家算法应该有了一点模糊的印象了,下面就深入一步的探究,为了方便,下面先就介绍银行家算法的数据结构。操作系统的资源可以是很多种,不同的进程对资源的需求也不同。

n : 进程的数量 m:资源的种类。

名词 数据结构
分配矩阵 Allocation[n][m]
最大需求矩阵 Max[n][m]
需求矩阵 Need[n][m]
可利用资源 Available[m]
请求资源 Request[n][m]

进程 i 对资源 j:

  • Allocation[i][j] 表示进程 i 已分配资源 j 的数量。

  • Max[i][j] 表示进程 i 对资源 j 的最大需求的数量。

  • Need[i][j] 表示进程 i 对资源j剩下的需求(Max[i][j] - Allocation[i][j] )。

  • Available[j] 对各个进程经过一番资源的分配后,资源 j 的数量。

  • Request[i][j] 进程 i 对资源 j 的请求数量。

这里要区分请求和需求。可以这样理解,请求是动态、不确定的,进程对资源的请求有时多有时少。

银行家算法的流程

回到前面,先假设当前系统是处于一个正常周转的状态,这时一个进程 i 发出资源请求,系统能否分配给它要经历如下步骤:

  1. 进程 i 的资源请求过度了吗?要知道一个进程在最初始状态是声明了最大的资源请求的。用数据结构表示就是:Request[i][j] < Need[i][j]。如果满足就继续往下,不满足就拒绝分配。不满足,通俗讲就是此时进程 i 的资源请求是过分的,撕毁条约,得寸进尺。

  2. 系统当前的资源情况能满足进程i的资源请求吗?经过步骤一,这时进程 i 的请求是合理的。但是这时也不能给它分配,要判断一下此时资源够不够?现在也不考虑资源周转的问题,当务之急是当前资源能否满足进程 i 的请求。如果可以,就继续往下,不可以则进程需要等待,直到系统有足够的资源再说。

  3. 系统处于安全状态吗?经过步骤一、二,进程 i 能否得到系统的资源分配还需要经过最后一道难关:系统将资源分配给该进程 i 后,还能处于一个安全状态吗?或者说,系统还能进行正常的资源周转吗? 这个地方可以说是整个算法的重中之重了。粗略来讲:系统先尝试对该进程 i 进行资源分配,然后进行安全性检测, 如果系统安全则分配成功,否则则撤销分配。详细的过程我下面再讲。

银行家算法中的安全性检测

上面将的数据结构、算法流程其实都是很容易理解的,但就判断当前系统是否安全可能还懵懵懂懂:到底怎么进行安全性检测?我觉得这部分应该是整个算法最关键的地方,只要干掉它,就 OK 了!

前面讲了系统先对该进程尝试进行资源分配(注意是尝试!),就会得到新的资源情况,更新的过程我们可以看看,对进程 i 进行资源分配 Request[i][j],资源更新情况如下:

Need[i][j] = Need[i][j] - Request[i][j] Allocation[i][j] = Allocation[i][j] + Request[i][j] Available[j] = Available[j] - Request[i][j]

(0 <= i<n,0 <= j < m) 下标从 0 开始

然后资源更新后的系统进行安全性检测,具体我们先看一个例子:

Process Allocation Need Available
P0 0 0 3 2 0 0 1 2 1 6 2 2
P1 1 0 0 0 1 7 5 0
P2 1 3 5 4 2 3 5 6
P3 0 3 3 2 0 6 5 2
P4 0 0 1 4 0 6 5 6

问:该状态是不是安全状态?

我们是先找出一个进程,使得系统可利用的资源能够它的所有资源需求

可以看到只有 P0 满足要求,就把 p0 加入安全队列中,然后将它以前占用的所有资源收回。这个时候,Available = Available + Allocation,即:Available: 1 6 2 2 + 0 0 3 2 = 1 6 5 4

Need 中减少 P0 进程

Need= \begin{bmatrix} 1&7&5&0\\ 2&3 &5& 6\\ 0& 6& 5& 2\\ 0 &6 &5& 6 \end{bmatrix}

又接着找一个进程,看是否满足:系统可利用的资源满足它的所有资源需求。

可以看到,P3 Need = 0 6 5 2 满足要求,P4 Need = 0 6 5 6 也满足要求,将P3加入安全队列中。这里我们可以任意选择一个,我们选择 P3,Available = Available + Allocation,将 P3 的分配资源 Allocation 归还。P3 Allocation = 0 3 3 2,所以 Available: 1 6 5 4 + 0 3 3 2 = 1 9 8 6

Need= \begin{bmatrix} 1&7&5&0\\ 2&3 &5& 6\\ 0 &6 &5& 6 \end{bmatrix}

继续,可以看到 P1、P4 满足要求,选择 P1,将 P1 加入安全队列中:

P1 Allocation =1 0 0 0

所以 Available: 1 9 8 6 + 1 0 0 0 = 2 9 8 6

Need= \begin{bmatrix} 2&3 &5& 6\\ 0 &6 &5& 6 \end{bmatrix}

可以看到 P2 、P4 都满足要求,选择 P2,将 P2 加入安全队列中:

P2 Allocation =1 3 5 4

所以 Available: 2 9 8 6 + 1 3 5 4 =3 |12|13|10,选择 P4,将 P4 加入安全队列中:

P2 Allocation =0 0 1 4 Available:3 |12|13|10 + 0 0 1 4 =3 |12|14|14

到此为止,所有的进程都加入安全队列中,说明整个系统是处于安全状态的,如果没有进程加入安全队列中,说明系统是不安全的,可能会发生死锁,银行家算法是避免死锁而出名的一种算法,由此可见一斑。

总结

安全性检测这部分应该是银行家算法的重中之重了,将逻辑搞清楚应该是不难的。具体的思路是:如果找到一个进程,使得当前可利用资源(Available)能够满足它的需求(Need),就先对其分配资源,然后收回分配给它之前的资源(Allocation),接着更新 Available(Available+=Allocation),然后将其加入安全性序列。

继续找一个进程,重复上面操作。需要注意的是,必须要循环多次,因为前面没有符合条件的进程可能因为后面的资源更新又符合条件了。最后,临界条件是如果循环一遍后,还是找不到符合条件的进程,那么说明系统不安全,退出循环,反之如果所有的进程都加入安全性序列,就说明此系统是安全的,退出循环。