1、银行家算法的工作原理
银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金。
操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。
2、银行家算法流程图
步骤:进程i发出请求资源申请,
(1)如果Request [j]<=need[i,j],转向步骤(2),否则认为出错,因为他所需要的资源数已 经超过它所宣布的最大值。
(2)如果:Request i[j]<=available[i,j],转向步骤(3),否则表示尚无足够资源,进程i需等待。
(3)若以上两个条件都满足,则系统试探着将资源分配给申请的进程,并修改下面数据结构中的数值:Available[i,j]= Available[i,j]- Request [j];
Allocation[i][j]= Allocation[i][j]+ Request [j];
need[i][j]= need[i][j]- Request [j];
(4)试分配后,执行安全性检查,调用check()函数检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程;否则本次试探分配作废,恢复原来的资源分配状态,让该进程等待。
(5)用do{…}while循环语句实现输入字符y/n判断是否继续进行资源申请。
3、安全性检查流程图:
步骤: (1).设置两个工作向量 Work=Available; FINISH
(2).从进程集合中找到一个满足下述条件的进程,FINISH ==false; Need <= Work;
如找到,执行(3);否则,执行(4)
(3).设进程获得资源,可顺利执行,直至完成,从而释放资源。
Work += Allocation; Finish=true;go to 2
(4).如所有的进程Finish= true,则表示安全;否则系统不安全。
3、代码
Banker.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define M 10
#define N 10
#pragma once
typedef int Bdatetype;
typedef struct Node
{
Bdatetype _request[M][N];//请求资源
Bdatetype _available[M][N];//可获得的
Bdatetype _need[M][N];//需要
Bdatetype _max[M][N];//最大
Bdatetype _allocation[M][N]; //已分配
Bdatetype _finish[M][N];//是否完成
Bdatetype _work[M][N];
Bdatetype _count[N];//计数
Bdatetype _sum[M][N];//可以提供的资源数
size_t size;//进程数量
size_t resource;//资源数
}Node;
void Bankerinit(Node* psl); //初始化
void Print();//
void Display(Node* psl, Bdatetype size, Bdatetype resource);
void Nodepush(Node* psl, Bdatetype size, Bdatetype resource);
void request(Node* psl, Bdatetype size, Bdatetype resource, Bdatetype input);
int safetytest(Node psl, Bdatetype size, Bdatetype resource);
Banker.c
#include"banker.h"
void Bankerinit(Node* psl){
size_t i = 0, j = 0;
for (i = 0; i < M; ++i)
for (j = 0; j < N; ++j) {
psl->_allocation[i][j] = psl->_available[0][j] = psl->_need[i][j] = psl->_max[i][j]=psl->_work[0][j] =psl->_finish[i][0]=psl->_sum[i][j]=psl->_request[i][j]= 0;
}
psl->size=psl->resource= 0;
}
void Print() {
printf("*************************************\n");
printf("***********1.输入 **************\n");
printf("***********2.请求资源 ************\n");
printf("***********3.展示 **************\n");
printf("***********4.安全性检验 **************\n");
printf("***********0.退出 **************\n");
printf("*************************************\n");
}
void request(Node* psl, Bdatetype size, Bdatetype resource,Bdatetype input) { //执行请求资源
size_t j = 0, i = 0;
int tmp = 0;
int input1= input - 1;
int need[M][N] = { 0 };
int available[M][N] = { 0 };
int allocation[M][N] = { 0 };
printf("请输入进程的请求资源数:\n");
for (j = 0; j < resource; ++j) {
scanf("%d", &psl->_request[input1][j]);
}
for (j = 0; j < resource; ++j) { //存在一个请求大于需求就返回
if (psl->_request[input1][j] > psl->_need[input1][j])
{
printf("请求大于需求\n");
return;
}
}
for (j = 0; j < resource; ++j) { //存在一个请求大于可用就返回
if (psl->_request[input1][j] > psl->_available[0][j]) {
printf("请求大于可用\n");
return;
}
}
//本次所需资源请求全部符合条件
for (j = 0; j < resource; ++j)
{
need[input1][j] = psl->_need[input1][j];
allocation[input1][j] = psl->_allocation[input1][j];
available[0][j] = psl->_available[0][j]; //存储本次进程的情况
psl->_available[0][j] -= psl->_request[input1][j];
psl->_allocation[input1][j] = psl->_allocation[input1][j] + psl->_request[input1][j];//更新本次请求进程的情况
psl->_need[input1][j] = psl->_need[input1][j] - psl->_request[input1][j];
tmp += psl->_need[input1][j];
}
if (tmp==0) {
for (j = 0; j < resource; ++j) {
psl->_available[0][j] += psl->_allocation[input1][j];
psl->_allocation[input1][j] = 0;
}
}
if (safetytest(*psl, size, resource) == 0) { //分配失败要将刚刚的进程情况还原
for (j = 0; j < resource; ++j)
{
psl->_need[input1][j] = need[input1][j];
psl->_allocation[input1][j] = allocation[input1][j];
psl->_available[0][j] = available[0][j];
}
}
else
{
printf("分配成功\n");
}
}
int safetytest(Node psl, Bdatetype size, Bdatetype resource) { //安全性检验
size_t j = 0, i = 0, k = 0;
int flag = 1;
int count = 0, num = 0;
for (j = 0; j < resource; ++j) //work =ava
{
psl._work[0][j] = psl._available[0][j];
}
for (i = 0; i < size; ++i) //finish =0
{
psl._finish[i][0] = 0;
}
while (num < size) {
for (i = 0; i < size; ++i) {
flag = 1;
if (psl._finish[i][0] == 0){
for (j = 0; j < resource; ++j)
{
if (psl._work[0][j] < psl._need[i][j]) { //存在一组不符合条件的就跳出循环
flag = 0;
break;
}
}
if (flag)
{ //当flag为1时,表示所有可用资源的数量一定小于need
for (j = 0; j < resource; ++j) {
psl._work[0][j] += psl._allocation[i][j];
}
psl._finish[i][0] = 1; //将此进程标注为true
psl._count[count] = i; //统计安全进程序列
++num; //计数
++count;//统计安全序列
k = 1;
break;
}
}
}
if (k == 0)
{ //循环比较
printf("不安全\n");
return 0;
}
k = 0;
}
printf("安全序列\n"); //输出安全序列
for (i = 0; i < size; ++i) {
printf("p%d ", psl._count[i]+1);
}
printf("\n");
return 1;
}
void Nodepush(Node* psl, Bdatetype size, Bdatetype resource) { //输入资源情况
Bdatetype i ,j= 0;
for (j = 0; j < resource;++j) {
printf("请输入第 %d 资源的sum\n", j + 1);
scanf("%d", &psl->_sum[0][j]);
}
for (i = 0; i < size; ++i) {
printf("请输入第%d个进程的资源分配情况\n", i + 1);
for (j = 0; j < resource; ++j) {
printf("请输入第 %d 个资源max的值\n", j + 1);
scanf("%d", &psl->_max[i][j]);
}
for (j = 0; j < resource; ++j) {
printf("请输入第 %d 个资源allocation的值\n", j + 1);
scanf("%d", &psl->_allocation[i][j]);
psl->_need[i][j] = psl->_max[i][j] - psl->_allocation[i][j];
}
for (j = 0; j < resource; ++j) {
psl->_available[0][j] = psl->_sum[0][j] -= psl->_allocation[i][j];
}
}
}
void Display(Node* psl, Bdatetype size, Bdatetype resource) {//展示各个资源情况
size_t i, j = 0;
printf("| pid |work|max|allocation|need|available|finish\n");
for (i = 0; i < size; ++i) {
printf("|");
printf("P%d ", i + 1);
printf("|");
for (j = 0; j < resource; ++j) {
printf("%d ", psl->_work[0][j]);
}
printf("|");
for (j = 0; j < resource; ++j) {
printf("%d ", psl->_max[i][j]);
}
printf("|");
for (j = 0; j < resource; ++j) {
printf("%d ", psl->_allocation[i][j]);
}
printf("|");
for (j = 0; j < resource; ++j) {
printf("%d ", psl->_need[i][j]);
}
printf("|");
for (j = 0; j < resource; ++j) {
printf("%d ", psl->_available[0][j]);
}
printf("|");
for (j = 0; j < resource; ++j) {
printf("%d ", psl->_finish[i][0]);
}
printf("|");
printf("\n");
}
}
void test() {
Node psl;
Bdatetype input=0,size=0,resourse=0;
do
{
Print();
scanf("%d",&input);
switch (input) {
case 0:
printf("程序退出\n");
break;
case 1:
Bankerinit(&psl);
printf("请输入进程数和资源数\n");
scanf("%d %d", &size, &resourse);
Nodepush(&psl, size, resourse);
break;
case 2:
printf("请输入进程号\n");
int input1 = 0;
scanf("%d", &input1);
request(&psl, size, resourse, input1);
break;
case 3:
Display(&psl, size, resourse);
break;
case 4:
safetytest(psl, size, resourse);
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
} while (input);
Bankerinit(&psl);
}
Test.c
#include"banker.h"
int main() {
test();
system("pause");
return 0;
}
4、实验结果展示
1.初始化输入
2.安全性检测
(1).给1号进程请求1 1
(2).不安全后展示原来资源情况
(3)给3号进程请求 1 1
更新后的结果
(4)情况综合展示
5、实验心得
最开始定义了一个结构体指针,但是我在输入数据的时候,没有&导致无法写入,在实现finish和available和request的时候最开始错误成定义成二维数组,双层循环的时候,无法使得值良好对应。最后还是改成一个“一维数组”。
在安全性算法的时候,最开始传值的时候用的是地址,导致最后如果不安全,还得恢复,所以这里直接建立临时拷贝,如果不安全,也不会影响结构体指针里的本来的值,所以就不用预存数据了。但是这样做的时候,在请求分配的时候,预分配之后,如果不安全还是的改回去,所以建立一个临时的数组,储存初值,在不安全的时候,直接拷贝恢复,谨记要考虑到回收的问题。
算法的实现还是比较简单的,但是要注意实现的过程中,将各个数组的资源情况熟悉,我在写的时候,由于开始思路不好,导致多次修改,所以写代码的时候,一定要有一个清晰的思路,再动手写,避免后续出现问题。
我建议先写一个完整的流程图,这样对后续代码的实现非常有好处。目前代码能够完整的实现老师的要求,如果后续出现问题,欢迎各位留言告诉我。