阅读更多
1 需求分析
1.1 银行家算法的实现思想
允许进程动态地申请资源,系统在每次实施资源分配之前,先计算资源分配的安全性,若此次资源分配安全(即资源分配后,系统能按某种顺序来为每个进程分配其所需的资源,直至最大需求,使每个进程都可以顺利地完成),便将资源分配给进程,否则不分配资源,让进程等待
1.2 死锁的概念
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
银行家算法是避免死锁的一种重要方法。操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配
1.3 产生死锁的必要条件
- 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放
- 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放
- 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放
- 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合
{P0, P1, P2, ..., Pn}
中的P0
正在等待一个P1
占用的资源;P1
正在等待P2
占用的资源,…,Pn
正在等待已被P0
占用的资源
1.4 功能实现
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何能够不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源,在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配。因此,对资源的分配要给予合理的规划
2 概要设计
2.1 数据结构
- 可利用资源向量Available:这是一个含有m个元素的数组,其中的而每一个元素代表一类可利用资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态的改变。如果
Available[j] = K
,则表示系统中现有Rj类资源
的数目为K
- 最大需求矩阵Max:这是一个n*m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果
Max[i][j] = K
,则表示进程i
需要Rj类资源
的最大数目为K
- 分配矩阵Allocation:这也是一个n*m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果
Allocation[i][j] = K
,则表示进程i
当前已分得Rj类资源
的数目为K
- 需求矩阵Need:这也是一个n*m的矩阵,用以表示每一个进程尚需的各类资源数。如果
Need[i][j] = K
,则表示进程i
还需要Rj类资源
的数目为K
个,方能完成任务
- 上述三个矩阵间存在下述关系:
Need[i][j] = Max[i][j] - Allocation[i][j]
2.2 设计思路
第一部分:银行家算法模块
- 如果
Request <= Need
,则转向2;否则出错
- 如果
Request <= Available
,则转向3;否则等待
- 系统试探分配请求的资源给进程
- 系统执行安全性算法
第二部分:安全性算法模块
- 设置两个向量
Work = Available
:表示系统可提供给进程继续运行所需要的各类资源数目
Finish
:表示系统是否有足够资源分配给进程
- 若
Finish[i] == False && Need <= Work
(i为资源类别),则执行3;否则执行4
- 进程P获得第i类资源,则顺利执行直至完成,并释放资源:
Work = Work + Allocation
以及Finish[i] = true
;转2
- 若所有进程的
Finish[i] == true
,则表示系统安全;否则不安全!
2.3 系统安全性判断
什么叫做系统安全性:即不会产生死锁的条件,所有的进程都能够按照一定顺序结束运行。某个时刻,某一进程的完成不依赖于其他进程所占有的资源。
详细过程与解释如下(类似于一个BFS遍历有向图的过程,每次访问degree为0的节点)
- 以进程i1为例,进程i1对资源j的需求量为
Need[i1][j]
,如果对于所有资源,均满足Need[i1][j] <= Available[j]
,意味着进程i1的完成只需要从系统剩余资源中获取即可,并不需要其他进程让出资源,因此进程i1是安全的,于是进程i1在当前状态下是可独立完成的,其完成的顺序记为1
- 现在我们需要假设进程i1完成了,那么在进程i1完成的基础上,是否有其他进程也能够独立完成任务?此时我们需要将i1占有的资源全部退还到Available中,即对所有资源执行
Available[j] += Allocation[i][j]
。那么在Available的新状态下,如果进程i2对于所有资源均满足Need[i2][j] <= Available[j]
,意味着进程i2的完成只需要从系统剩余资源中获取即可,并不需要其他进程让出资源,因此进程i2也是安全的,于是进程i2在当前状态下是可独立完成的,其完成的顺序记为2
- 重复上述步骤…直至所有进程均可完成(安全状态)或者存在某个或某些进程无法完成(不安全状态)
3 Java源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
| package org.liuyehcf.other;
import java.util.Arrays; import java.util.Random;
public class BankAlgorithm {
private static final int RESOURCE_NUM = 3;
private static final int PROCESS_NUM = 10;
private int[] total;
private int[] available;
private int[][] max;
private int[][] allocation;
private int[][] need;
private boolean[] state;
private boolean[] finished;
private int finishedCnt;
private int[] pause;
private Random random = new Random();
public void serve() { initialize();
while (finishedCnt != PROCESS_NUM) { int processId = getRandomProcessId();
int[] request = getRandomRequest(processId);
check(); requestResource(processId, request); check(); } }
private void initialize() { total = new int[RESOURCE_NUM]; available = new int[RESOURCE_NUM]; max = new int[PROCESS_NUM][RESOURCE_NUM]; allocation = new int[PROCESS_NUM][RESOURCE_NUM]; need = new int[PROCESS_NUM][RESOURCE_NUM]; state = new boolean[PROCESS_NUM]; finished = new boolean[PROCESS_NUM]; pause = new int[RESOURCE_NUM];
finishedCnt = 0;
Arrays.fill(total, 10); Arrays.fill(available, 10); for (int i = 0; i < PROCESS_NUM; i++) { for (int j = 0; j < RESOURCE_NUM; j++) { max[i][j] = random.nextInt(5) + 1; need[i][j] = max[i][j]; } } }
private int getRandomProcessId() { int remainProcessNum = PROCESS_NUM - finishedCnt;
int index = random.nextInt(remainProcessNum);
for (int i = 0; i < PROCESS_NUM; i++) { if (finished[i]) continue; if (index-- == 0) { return i; } } throw new RuntimeException(); }
private int[] getRandomRequest(int processId) { int[] request = new int[RESOURCE_NUM];
for (int j = 0; j < RESOURCE_NUM; j++) { request[j] = random.nextInt(Math.min(available[j], need[processId][j]) + 1); }
return request; }
private void requestResource(int processId, int[] request) { for (int j = 0; j < RESOURCE_NUM; j++) { if (request[j] > need[processId][j]) { throw new RuntimeException(); } if (request[j] > available[j]) { throw new RuntimeException(); } }
for (int j = 0; j < RESOURCE_NUM; j++) { available[j] -= request[j]; allocation[processId][j] += request[j]; need[processId][j] -= request[j]; }
if (isSafeState()) { System.err.println("Safe!"); int count = 0;
for (int j = 0; j < RESOURCE_NUM; j++) { if (need[processId][j] == 0) { count++; } }
if (count == RESOURCE_NUM) { for (int j = 0; j < RESOURCE_NUM; j++) { available[j] += allocation[processId][j]; allocation[processId][j] = 0; need[processId][j] = max[processId][j]; } finishedCnt++; finished[processId] = true; System.out.println("Process " + processId + " is finished!"); } } else { System.err.println("Not safe!"); for (int j = 0; j < RESOURCE_NUM; j++) { available[j] += request[j]; allocation[processId][j] -= request[j]; need[processId][j] += request[j]; } } }
private boolean isSafeState() {
System.arraycopy(available, 0, pause, 0, RESOURCE_NUM); Arrays.fill(state, false);
boolean canBreak = false; while (!canBreak) { canBreak = true; for (int i = 0; i < PROCESS_NUM; i++) { if (finished[i]) { state[i] = true; continue; } int count = 0; for (int j = 0; j < RESOURCE_NUM; j++) { if (need[i][j] <= pause[j]) { count++; } }
if (!state[i] && count == RESOURCE_NUM) { state[i] = true; canBreak = false; for (int j = 0; j < RESOURCE_NUM; j++) { pause[j] += allocation[i][j]; } } } }
int safeProcessNum = 0;
for (boolean b : state) { safeProcessNum += (b ? 1 : 0); }
return safeProcessNum == PROCESS_NUM; }
private void check() { for (int i = 0; i < PROCESS_NUM; i++) { for (int j = 0; j < RESOURCE_NUM; j++) { if (max[i][j] != need[i][j] + allocation[i][j]) throw new RuntimeException(); if (max[i][j] > total[j]) throw new RuntimeException(); } }
if (!isSafeState()) throw new RuntimeException(); }
public static void main(String[] args) { BankAlgorithm bankAlgorithm = new BankAlgorithm();
bankAlgorithm.serve(); } }
|
4 参考