银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。
背景知识
在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。在这样的描述中,银行家就好比操作系统,资金就是资源,客户就相当于要申请资源的进程。
银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。
要解释银行家算法,必须先解释操作系统安全状态和不安全状态。
安全序列是指一个进程序列{P1,…,Pn}是安全的,即对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源量之和。
安全状态
- 如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
不安全状态
- 不存在一个安全序列。不安全状态不一定导致死锁。
数据结构
- 可利用资源向量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]
算法原理
我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
- 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
- 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
- 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
- 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.
操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。
代码实现
//#include <stdafx.h>
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#pragma warning(disable:4996)
#define MAX_PROCESS 10 //进程数上限
#define MAX_RESOURCE_KIND 10 //资源种类上限
#define MAX_RESOURCE_NUM 20 //每种资源可用数上限
int resource; //实际资源种类数
int process; //实际进程数
int safe_list[MAX_PROCESS]; //安全序列
struct AVAILABLE { //可用资源向量
int resource_number; //资源数目
int work; //工作向量
}Resource[MAX_RESOURCE_KIND], R_backup[MAX_RESOURCE_KIND];
struct PROC { //进程数据向量表
int max[MAX_RESOURCE_KIND]; //最大需求矩阵
int allocation[MAX_RESOURCE_KIND]; //分配矩阵
int need[MAX_RESOURCE_KIND]; //需求矩阵
bool finish; //满足标记
}Process[MAX_PROCESS], P_backup[MAX_PROCESS];
void zero();
void show_me();
void init();
void init_allocation();
void update();
void backup();
void re_backup();
bool allocation();
bool one_allocation(int a, int b, int c);
bool release();
bool one_release(int a, int b, int c);
int is_safe();
void test();
int banker();
void menu();
void zero() {//清零
for (int i = 0; i<MAX_RESOURCE_KIND; i++) {
Resource[i].resource_number = 0;
}
for (int i = 0; i<MAX_RESOURCE_KIND; i++) {
for (int j = 0; j< MAX_RESOURCE_KIND; j++) {
Process[i].max[j] = 0;
Process[i].allocation[j] = 0;
Process[i].need[j] = 0;
}
}
}
void show_me() {//绘制矩阵
printf("\n Available矩阵 ");
for (int i = 0; i < resource; i++) {
printf("%d ", Resource[i].resource_number);
}
printf("\n");
printf("\n Max矩阵");
for (int i = 0; i < MAX_RESOURCE_KIND * 2 - 7; i++) printf(" ");
printf("Allocation矩阵");
for (int i = 0; i < MAX_RESOURCE_KIND * 2 - 14; i++) printf(" ");
printf("Need矩阵");
for (int i = 0; i < MAX_RESOURCE_KIND * 2 - 8; i++) printf(" ");
for (int i = 0; i<process; i++) {
printf("\n ");
for (int j = 0; j<resource; j++) printf("%d ", Process[i].max[j]);
for (int i = 0; i < MAX_RESOURCE_KIND * 2 - resource * 2; i++) printf(" ");
for (int j = 0; j<resource; j++) printf("%d ", Process[i].allocation[j]);
for (int i = 0; i < MAX_RESOURCE_KIND * 2 - resource * 2; i++) printf(" ");
for (int j = 0; j<resource; j++) printf("%d ", Process[i].need[j]);
}
printf("\n");
}
void init() {//初始化
int n;
printf("\n输入资源种类数 ");
scanf("%d", &n);
resource = n;
for (int i = 0; i<resource; i++) {
printf("\n输入第%d种资源数量 ", i + 1);
scanf("%d", &n);
Resource[i].resource_number = n;
}
printf("\n输入进程数 ");
scanf("%d", &n);
process = n;
for (int i = 0; i<process; i++) {
int a, flag;
flag = 0;
printf("\n输入进程%d各种资源最大需求数目 ", i + 1);//最大需求个数max
for (int j = 0; j<resource; j++) {
scanf("%d", &a);
Process[i].max[j] = a;
if (a>Resource[j].resource_number) flag = 1;
}
if (flag == 1) {
i--;
printf("\n需求超过资源上限请重新输入\n");
}
getchar();
}
}
void init_allocation() {//初始分配状态
for (int i = 0; i<process; i++) {
int a, flag;
flag = 0;
printf("\n输入进程%d当前资源占用情况 ", i + 1);
for (int j = 0; j<resource; j++) {
scanf("%d", &a);
Process[i].allocation[j] = a;
if (a>Resource[j].resource_number) flag = 1;
}
if (flag == 1) {
i--;
printf("\n当前资源占用超过资源上限请重新输入\n");
}
}
update();
}
void update() {//更新需求矩阵need和资源向量allocation
for (int i = 0; i<process; i++) {
for (int j = 0; j<resource; j++) {
Process[i].need[j] = Process[i].max[j] - Process[i].allocation[j];
Resource[j].resource_number -= Process[i].allocation[j];
}
}
}
bool allocation()
{
backup();
printf("\n请输入 进程号以及对应资源所分配的数目用空格隔开\n");
int pro_num;
scanf("%d", &pro_num);
int aff[MAX_RESOURCE_KIND];
for (int i = 0; i < resource; i++)
{
scanf("%d", &aff[i]);
}
for (int i = 0; i < resource; i++)
{
if (one_allocation(pro_num - 1, i, aff[i]) == false)
{//调用单次分配函数尝试分配
re_backup();
return false;
}
}
return true;
}
bool one_allocation(int a, int b, int c) {//单次分配
if (c>Process[a].need[b])
{
printf("要求超过所需上限,请求失败\n");
return false;
}
else if (c>Resource[b].resource_number)
{
printf("无足够资源,请求失败\n");
return false;
}
Resource[b].resource_number -= c;
Process[a].need[b] -= c;
Process[a].allocation[b] += c;
return true;
}
void backup() { //数据备份
for (int i = 0; i < process; i++) {
P_backup[i] = Process[i];
}
for (int i = 0; i < resource; i++) {
R_backup[i] = Resource[i];
}
}
void re_backup() { //数据还原
for (int i = 0; i < process; i++) {
Process[i] = P_backup[i];
}
for (int i = 0; i < resource; i++) {
Resource[i] = R_backup[i];
}
}
bool release() { //释放资源
backup();
printf("\n请输入 进程号以及对应资源所分配的数目用空格隔开\n");
int pro_num;
scanf("%d", &pro_num);
int aff[MAX_RESOURCE_KIND];
for (int i = 0; i < resource; i++) {
scanf("%d", &aff[i]);
}
for (int i = 0; i < resource; i++) {
if (one_release(pro_num, i, aff[i]) == false) {
re_backup();
return false;
}
}
return true;
}
bool one_release(int a, int b, int c) {//资源释放
if (c>Process[a].allocation[b]) {
printf("释放超过所有上限,请求失败\n");
return false;
}
Resource[b].resource_number += c;
Process[a].need[b] += c;
Process[a].allocation[b] -= c;
return true;
}
int is_safe()
{ //安全性检测算法
for (int i = 0; i < resource; i++)
{
Resource[i].work = Resource[i].resource_number;//初始时,赋值work
}
for (int i = 0; i < process; i++)
{
Process[i].finish = false;
safe_list[i] = 0;
}
test();
bool flag = true;
for (int i = 0; i < process; i++)
{
if (Process[i].finish == false)
{
flag = false;
break;
}
}
if (flag == true)
{
printf("\n系统状态安全");
printf("\n安全序列为 ");
for (int i = 0; i < process; i++) {
printf("%d ", safe_list[i]);
}
return 1;
}
else {
printf("\n系统状态不安全");
return -1;
}
}
void test() { //安全性算法的递归分支
for (int i = 0; i < process; i++)
{
bool flag = true;
if (Process[i].finish == false)
{
for (int j = 0; j < resource; j++)
{
if (Process[i].need[j] > Resource[j].work)
{
flag = false;
break;
}
}
if (flag == true)
{
for (int j = 0; j < resource; j++)
{
Resource[j].work += Process[i].allocation[j];
Process[i].finish = true;
}
for (int k = 0; k < process; k++)
{
if (safe_list[k] == 0)
{
safe_list[k] = i + 1;
break;
}
}
test(); //递归处理
}
}
}
}
int banker() {//银行家算法
backup(); //备份
//allocation();
if (allocation() == false) return -1;
bool flag;
flag = is_safe();
if (flag == true)
{
char k[10];
printf("\n是否分配(y/n) ");
scanf("%s", &k);
if (_stricmp(k, "y") == 0) return 1;
else
{
re_backup();
return -1;
}
}
else {
re_backup();
return -1;
}
}
void menu() { //菜单函数
printf("\n请输入指令\n");
printf("\n初始化(init) \n显示数据矩阵(show) \n判断安全性(safe)\n申请资源(request) \n释放资源(release) \n退出(quit)\n清屏(clear)\n");
char code[20];
while (1) {
printf("\n");
scanf("%s", code);
if (_stricmp(code, "init") == 0) { //重置操作
zero();
init();
init_allocation();
}
else if (_stricmp(code, "show") == 0) { //显示功能
show_me();
}
else if (_stricmp(code, "safe") == 0) { //判断安全性
is_safe();
}
else if (_stricmp(code, "request") == 0) { //申请资源
printf("\n是否使用银行家算法保证安全性(y/n)\n");
scanf("%s", code);
if (_stricmp(code, "y") == 0) banker();
else allocation();
}
else if (_stricmp(code, "release") == 0) { //释放资源
release();
}
else if (_stricmp(code, "quit") == 0) { //退出
return;
}
else if (_stricmp(code, "clear") == 0) { //清屏
system("cls");
printf("\n请输入指令\n");
printf("\n初始化(init) \n显示数据矩阵(show) \n判断安全性(safe)\n申请资源(request) \n释放资源(release) \n退出(quit)\n清屏(clear)\n");
}
else printf("命令无效,请重新输入\n");
}
}
int main(int argc, char* argv[])
{
/* zero(); init(); init_allocation(); show_me(); is_safe();*/
menu();
getchar();
return 0;
}