[关闭]
@1405010304geshuaishuai 2016-04-21T09:56:43.000000Z 字数 5194 阅读 2709

实验五---银行家算法的模拟与实现

银行家算法


作者:葛帅帅
学号:1405010304
班级:三班


1、实验目的

(1) 进一步了解进程的并发执行。
(2) 加强对进程死锁的理解。
(3) 掌握使用银行家算法避免死锁问题。

2、实验内容

本实验的内容是要通过编写和调试一个模拟系统动态分配资源的银行家算法程序,有效地防止
和避免死锁发生。具体要求如下:
(1) 初始化时让系统拥有一定的资源;
(2) 用键盘输入的方式允许进程动态申请资源;
(3) 如果预分配后,系统处于安全状态,则修改系统的资源分配情况,正式分配资源;
(4) 如果预分配后,系统处于不安全状态,则提示不能满足请求,恢复原状态。银行家算法. 顾名思义是来源于银行的借贷业务,一定数量的本金要应多个客户的借贷周转,为了防止银行加资金无法周转而倒闭,对每一笔贷款,必须考察其是否能限期归还。在操作系统中研究资源分配策略时也有类似问题,系统中有限的资源要供多个进程使用,必须保证得到的资源的进程能在有限的时间内归还资源,以供其他进程使用资源。如果资源分配不当,就会发生进程循环等待资源,则进程都无法继续执行下去的死锁现象。把一个进程需要和已占有资源的情况记录在进程控制中,假定进程控制块PCB其中“状态”有就绪态、等待态和完成态。当进程在处于等待态时,表示系统不能满足该进程当前的资源申请。“资源需求总量”表示进在整个执行过程中总共要申请的资源量。显然,每个进程的资源求总量不能超过系统拥有的资源总数,使用银行算法进行资源分配可以避免死锁.

3、 银行家算法中的数据结构与流程图

数据结构
1)可利用资源向量 Available
是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=k,则表示系统中现有Rj类资源k个。
2)最大需求矩阵Max
这是一个n*m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=k,则表示进程i需要Rj类资源的最大数目为k.
3)分配矩阵Allocation
这也是一个n*m的矩阵,它定义了系统中每一类资源当前已分配给每一个进程的资源数。如果Allocation[i,j]=k,则表示进程i当前已分得Rj类资源的数目为k。
4)需求矩阵Need.
这也是一个n*m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=k,则表示进程i还需要Rj类资源k个,方能完成其任务。
Need[i,j]=Max[i,j]-Allocation[i,j]
流程图(见图5-8)
liucherngtu

4、 银行家算法编程实现

源程序 main.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "banker.h"
  4. //试探分配
  5. void ProbeAlloc(int process,RESOURCE *res)
  6. {
  7. Available.A -= res->A;
  8. Available.B -= res->B;
  9. Available.C -= res->C;
  10. Allocation[process].A += res->A;
  11. Allocation[process].B += res->B;
  12. Allocation[process].C += res->C;
  13. Need[process].A -= res->A;
  14. Need[process].B -= res->B;
  15. Need[process].C -= res->C;
  16. }
  17. //若试探分配后进入不安全状态,将分配回滚
  18. void RollBack(int process,RESOURCE *res)
  19. {
  20. Available.A += res->A;
  21. Available.B += res->B;
  22. Available.C += res->C;
  23. Allocation[process].A -= res->A;
  24. Allocation[process].B -= res->B;
  25. Allocation[process].C -= res->C;
  26. Need[process].A += res->A;
  27. Need[process].B += res->B;
  28. Need[process].C += res->C;
  29. }
  30. //安全性检查
  31. bool SafeCheck()
  32. {
  33. RESOURCE Work = Available;
  34. bool Finish[PROCESSES_NUMBER] = {false,false,false,false,false};
  35. int i;
  36. int j = 0;
  37. for (i = 0; i < PROCESSES_NUMBER; i++)
  38. {
  39. //是否已检查过
  40. if(Finish[i] == false)
  41. {
  42. //是否有足够的资源分配给该进程
  43. if(Need[i].A <= Work.A && Need[i].B <= Work.B && Need[i].C <= Work.C)
  44. {
  45. //有则使其执行完成,并将已分配给该进程的资源全部回收
  46. Work.A += Allocation[i].A;
  47. Work.B += Allocation[i].B;
  48. Work.C += Allocation[i].C;
  49. Finish[i] = true;
  50. safe[j++] = i;
  51. i = -1; //重新进行遍历
  52. }
  53. }
  54. }
  55. //如果所有进程的Finish向量都为true则处于安全状态,否则为不安全状态
  56. for (i = 0; i < PROCESSES_NUMBER; i++)
  57. {
  58. if (Finish[i] == false)
  59. {
  60. return false;
  61. }
  62. }
  63. return true;
  64. }
  65. //资源分配请求
  66. bool request(int process,RESOURCE *res)
  67. {
  68. //request向量需小于Need矩阵中对应的向量
  69. if(res->A <= Need[process].A && res->B <= Need[process].B && res->C <= Need[process].C)
  70. {
  71. //request向量需小于Available向量
  72. if(res->A <= Available.A && res->B <= Available.B && res->C <= Available.C)
  73. {
  74. //试探分配
  75. ProbeAlloc(process,res);
  76. //如果安全检查成立,则请求成功,否则将分配回滚并返回失败
  77. if(SafeCheck())
  78. {
  79. return true;
  80. }
  81. else
  82. {
  83. printf("安全性检查失败。原因:系统将进入不安全状态,有可能引起死锁。\n");
  84. printf("正在回滚...\n");
  85. RollBack(process,res);
  86. }
  87. }
  88. else
  89. {
  90. printf("安全性检查失败。原因:请求向量大于可利用资源向量。\n");
  91. }
  92. }
  93. else
  94. {
  95. printf("安全性检查失败。原因:请求向量大于需求向量。\n");
  96. }
  97. return false;
  98. }
  99. //输出资源分配表
  100. void PrintTable()
  101. {
  102. printf("\t\t\t*********资源分配表*********\n");
  103. printf("Process Max Allocation Need Available\n");
  104. printf(" A B C A B C A B C A B C\n");
  105. printf(" P0 %d %d %d %d %d %d %d %d %d %d %d %d\n",Max[0].A,Max[0].B,Max[0].C,Allocation[0].A,Allocation[0].B,Allocation[0].C,Need[0].A,Need[0].B,Need[0].C,Available.A,Available.B,Available.C);
  106. printf(" P1 %d %d %d %d %d %d %d %d %d\n",Max[1].A,Max[1].B,Max[1].C,Allocation[1].A,Allocation[1].B,Allocation[1].C,Need[1].A,Need[1].B,Need[1].C);
  107. printf(" P2 %d %d %d %d %d %d %d %d %d\n",Max[2].A,Max[2].B,Max[2].C,Allocation[2].A,Allocation[2].B,Allocation[2].C,Need[2].A,Need[2].B,Need[2].C);
  108. printf(" P3 %d %d %d %d %d %d %d %d %d\n",Max[3].A,Max[3].B,Max[3].C,Allocation[3].A,Allocation[3].B,Allocation[3].C,Need[3].A,Need[3].B,Need[3].C);
  109. printf(" P4 %d %d %d %d %d %d %d %d %d\n",Max[4].A,Max[4].B,Max[4].C,Allocation[4].A,Allocation[4].B,Allocation[4].C,Need[4].A,Need[4].B,Need[4].C);
  110. printf("\n");
  111. }
  112. int main()
  113. {
  114. int ch;
  115. printf("先检查初始状态是否安全。\n");
  116. if (SafeCheck())
  117. {
  118. printf("系统处于安全状态。\n");
  119. printf("安全序列是{P%d,P%d,P%d,P%d,P%d}。\n",safe[0],safe[1],safe[2],safe[3],safe[4]);
  120. }
  121. else
  122. {
  123. printf("系统处于不安全状态。程序将退出...\n");
  124. goto over;
  125. }
  126. do
  127. {
  128. int process;
  129. RESOURCE res;
  130. PrintTable();
  131. printf("请依次输入请求分配的进程和对三类资源的请求数量:");
  132. scanf("%d%d%d%d",&process,&res.A,&res.B,&res.C);
  133. if (request(process,&res))
  134. {
  135. printf("分配成功。\n");
  136. printf("安全序列是{P%d,P%d,P%d,P%d,P%d}。\n",safe[0],safe[1],safe[2],safe[3],safe[4]);
  137. }
  138. else
  139. {
  140. printf("分配失败。\n");
  141. }
  142. printf("是否继续分配?(Y/N):");
  143. fflush(stdin); //虽然C标准不支持这种用法,但是VC++支持
  144. ch = getchar();
  145. } while (ch == 'Y' || ch == 'y');
  146. over:
  147. printf("执行完毕。");
  148. return 0;
  149. }

头文件 banker.h
定义一个结构体
数据初始化三个矩阵和一个向量。

  1. typedef int bool;
  2. #define false 0
  3. #define true !false
  4. //系统中所有进程数量
  5. #define PROCESSES_NUMBER 5
  6. typedef struct {
  7. int A;
  8. int B;
  9. int C;
  10. }RESOURCE;
  11. //最大需求矩阵
  12. RESOURCE Max[PROCESSES_NUMBER] =
  13. {
  14. {7,5,3},
  15. {3,2,2},
  16. {9,0,2},
  17. {2,2,2},
  18. {4,3,3}
  19. };
  20. //已分配资源数矩阵
  21. RESOURCE Allocation[PROCESSES_NUMBER] =
  22. {
  23. {0,1,0},
  24. {2,0,0},
  25. {3,0,2},
  26. {2,1,1},
  27. {0,0,2}
  28. };
  29. //需求矩阵
  30. RESOURCE Need[PROCESSES_NUMBER] =
  31. {
  32. {7,4,3},
  33. {1,2,2},
  34. {6,0,0},
  35. {0,1,1},
  36. {4,3,1}
  37. };
  38. //可用资源向量
  39. RESOURCE Available = {3,3,2};
  40. int safe[PROCESSES_NUMBER];

5、 实验结果与分析

运行结果见图 5-9
result last

6、 实验总结

了解避免死锁方法--银行家算法
首先要定义一些结构体
结构体里面的三个域分别表示三种资源的数量。
数据初始化三个矩阵和一个向量。
为了能够输出安全状态时的安全序列,还可以添加一个记录安全序列的数组int SafeSequence[PROCESSED_NUMBER]。

  因为银行家算法使用的是试探分配的策略,如果进程请求分配的资源既不大于自己尚需的资源,又不大于系统现存的资源,那就可以先试探着将资源分配给该进程,然后测试分配后是不是有可能造成死锁,如果不会引起死锁(即安全状态)就可以完成分配,否则(即不安全状态)就将试探分配的资源回收回来让其等待。那么根据上面定义的数据就可以很容易的写出试探分配和回收资源的函数。
  接下来就是安全性检查函数了,在这个函数中还需要设置一个Work向量和一个Finish向量,函数实现主要就是通过一个for循环检查试探分配后系统的可用资源数是否能满足所有进程的需求,若能满足某一个进程的需求,则假设分配其所需资源使之完成运行,然后就可以将资源回收以分配给其它进程,如果依照这种方法所有的进程都可以成功执行,那么现在的状态就是安全状态,否则即为不安全状态,有可能引起死锁。
  有了以上三个函数就可以写出请求分配资源的函数了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注