死鎖/02.銀行家算法.md


  銀行家算法所避免的死鎖問題並不是我們常說的mutex鎖問題,而是爲了讓系統處於安全狀態,因爲安全狀態是一定不會出現死鎖的。

1.系統安全狀態

安全狀態指的是系統能按某種進程推進順序(P1,P2,…,Pn)爲每個進程分配其所需的資源,直至滿足每個進程對資源的最大需求,使每個進程都可順利地完成。此時,序列(P1,P2,…,Pn)爲安全序列。如果系統無法找到這樣一個序列,則稱系統處於不安全狀態。
  雖然並非所有的不安全狀態都必然會轉爲死鎖狀態,但當系統進入不安全狀態,就有可能進入死鎖。反之,只要系統處於安全狀態,就不會進入死鎖狀態。因此,避免死鎖的實質在於,系統在進行資源分配時,應使系統不進入安全狀態。
  所以,只要存在一種分配序列時,系統就是安全的。

2.銀行家算法描述

2.1算法數據結構

該算法需要維護多個數組,別看下面字多,內容很簡單。因爲一個進程運行需要的資源不止一種(例如內存、CPU等等),這裏有m種,一共有n個進程。

(1)Avaliable
可利用資源向量,是一個含有m個元素的數組,其中每一個元素代表一類可利用的資源數目,初始值是系統中所分配的該類全部可用資源的數目,其數值隨該類資源的分配和回收而改變。
(2)Max
最大需求矩陣,是一個n*m的矩陣,定義了系統中n個進程中的每一個進程對m類資源的最大需求。
(3)Allocation
分配矩陣,是一個n*m的矩陣,定義了系統中每一類資源當前分配給每一進程的資源數。
(4)Need
需求矩陣,是一個n*m的矩陣,表示每一個進程尚需的各類資源數。

有以下關係:
Need[i,j]=Max[i,j]Allocation[i,j] Need[i,j]=Max[i,j]-Allocation[i,j]

2.2 算法內容

設 Request;是進程Pi的請求向量,如果 Requesti[j] = K,表示進程Pi需要K個Rj類型的資源。當Pi發出資源請求後,系統按下述步驟進行檢査:
  (1) 如果 Requesti[j] ≤ Need[i,j]便轉向步驟(2);否則認爲出錯,因爲它所需要的資源數已超過它所宣佈的最大值。
  (2) 如果 Requesti[j] ≤ Available[j],便轉向步驟(3);否則,表示尚無足夠資源,Pi須等待。
  (3) 系統試探着把資源分配給進程Pi,並修改下面數據結構中的數值
    Available[j] = Available[j] - Requesti[j];
    Allocation[i,j] = Allocation[i,j] + Requesti[j];
    Need[i,j] = Need[i,j] - Requesti[j];
  (4) 系統執行安全性算法,檢查此次資源分配後系統是否處於安全狀態。若安全,才正式將資源分配給進程Pi,以完成本次分配;否則,將本次的試探分配作廢,恢復原來的資源分配狀態,讓進程Pi等待。
計算機操作系統_銀行家算法

2.3 安全性算法

本部分爲僞代碼

系統所執行的安全性算法可描述如下:
  (1) 設置兩個向量:①工作向量Work,它表示系統可提供給進程繼續運行所需的各類資源數目,它含有m個元素,在執行安全算法開始時,Work = Available;② Finish:它表示系統是否有足夠的資源分配給進程,使之運行完成。開始時先做 Finish[i] = false;當有足夠資源分配給進程時,再令Finish[i] = true。
  (2) 從進程集合中找到一個能滿足下述條件的進程
    ① Finish[i] = false;
    ② Need[i,j] ≤ Work[j];
若找到,執行步驟(3),否則,執行步驟(4)。
  (3)當進程Pi獲得資源後,可順利執行,直至完成,並釋放出分配給它的資源,故應執行:
    Work[j] = Work[j] + Allocation[i,j];
    Finish[i] = true;
    go to step 2;(goto語句不推薦使用 _ )
  (4)如果所有進程的 Finish[i] =true都滿足,則表示系統處於安全狀態;否則,系統處於不安全狀態。
計算機操作系統_銀行家算法

2.4 實例

因爲不實用,我就不自己寫代碼了,完了看還沒看懂,完蛋玩意。下面這個哥們特屌,看看他的把。我覺得這塊也不用看,如果面試問就是了解過,具體沒寫過,這就是這樣嘛。

本程序的難點在於安全性算法,對於一個安全的系統來說,此步驟較爲容易,難在於判斷不安全的系統。爲什麼這麼說呢?由於本程序再設計尋找安全序列的部分使用while循環,就需要找到分別處理安全系統與不安全系統的終止循環條件,對於安全的系統,滿足條件 Finish[i] = false 和 Need[i,j] ≤ Work[j] 的,必定也會按照預期的將 Finish[i] 向量全部置爲true,那是不是就可以設置一個變量來累加計數,當該變量與進程數量相等的時候,就說明已經全部置爲true了,終止循環,也就是說系統安全。
  對於不安全的系統,上述方法肯定是不行的,因爲不可能將向量 Finish[i] 都置爲 true ,必定存在 false。就得尋求一個跳出循環的條件,但是由於需要不斷循環查找並嘗試分配,尋求一個安全序列,到底該怎麼算是已經找不到安全路徑了呢?下面說本程序的解決辦法,首先需要想到的是,當我們尋找一輪都沒有找到一個可以安全執行的進程,是不是就說明往後也找不到了呢?沒錯,就是這樣的!所以我們每次在記錄 Finish[i] = true 的次數的時候,不妨把這個次數再使用另一個變量存放起來,然後在判斷語句當中判斷當尋找一輪下來,該值未發生改變,說明已經找不到安全的進程了,即可跳出循環,該系統不安全!

avatar
  再貼一下這哥們的源碼

#include<stdio.h>
#define resourceNum 3
#define processNum  5

//系統可用(剩餘)資源
int available[resourceNum]={3,3,2};
//進程的最大需求
int maxRequest[processNum][resourceNum]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};
//進程已經佔有(分配)資源
int allocation[processNum][resourceNum]={{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};
//進程還需要資源
int need[processNum][resourceNum]={{7,4,3},{1,2,2},{6,0,0},{0,1,1},{4,3,1}};
//是否安全
bool Finish[processNum];
//安全序列號
int safeSeries[processNum]={0,0,0,0,0};
//進程請求資源量
int request[resourceNum];
//資源數量計數
int num;

//打印輸出系統信息
void showInfo()
{
	printf("\n------------------------------------------------------------------------------------\n");  
	printf("當前系統各類資源剩餘:");
	for(int j = 0; j < resourceNum; j++)
	{
		printf("%d ",available[j]);
	}
	printf("\n\n當前系統資源情況:\n");
	printf(" PID\t Max\t\tAllocation\t Need\n");
	for(int i = 0; i < processNum; i++)
	{
		printf(" P%d\t",i);
		for(int j = 0; j < resourceNum; j++)
		{
			printf("%2d",maxRequest[i][j]);
		}
		printf("\t\t");
		for(j = 0; j < resourceNum; j++)
		{
			printf("%2d",allocation[i][j]);
		}
		printf("\t\t");
		for(j = 0; j < resourceNum; j++)
		{
			printf("%2d",need[i][j]);
		}
		printf("\n");
	}
}

//打印安全檢查信息
void SafeInfo(int *work, int i)
{
	int j;
	printf(" P%d\t",i);
	for(j = 0; j < resourceNum; j++)
	{
		printf("%2d",work[j]);
	}   
	printf("\t\t");
	for(j = 0; j < resourceNum; j++)
	{
		printf("%2d",allocation[i][j]);
	}
	printf("\t\t");
	for(j = 0; j < resourceNum; j++)
	{
		printf("%2d",need[i][j]);
	}
	printf("\t\t");
	for(j = 0; j < resourceNum; j++)
	{
		printf("%2d",allocation[i][j]+work[j]);
	}
	printf("\n");
}

//判斷一個進程的資源是否全爲零
bool isAllZero(int kang)
{
	num = 0;
	for(int i = 0; i < resourceNum; i++ )
	{
		if(need[kang][i] == 0)
		{
			num ++;
		}
	}
	if(num == resourceNum)
	{
		return true;
	}
	else
	{
		return false;
	}   
}

//安全檢查
bool isSafe()
{
	//int resourceNumFinish = 0;
	int safeIndex = 0;
	int allFinish = 0;
	int work[resourceNum] = {0};
	int r = 0;
	int temp = 0;
	int pNum = 0;
	//預分配爲了保護available[]
	for(int i = 0; i < resourceNum; i++)
	{		
		work[i] = available[i];	
	}
	//把未完成進程置爲false
	for(i = 0; i < processNum; i++)
	{
		bool result = isAllZero(i);
		if(result == true)
		{
			Finish[i] = true;
			allFinish++;
		}
		else
		{
			Finish[i] = false;
		}

	}
	//預分配開始
	while(allFinish != processNum)
	{
		num = 0;	
		for(i = 0; i < resourceNum; i++)
		{
			if(need[r][i] <= work[i] && Finish[r] == false)
			{
				num ++;
			}			
		}
		if(num == resourceNum)
		{		
			for(i = 0; i < resourceNum; i++ )
			{
				work[i] = work[i] + allocation[r][i];
			}
			allFinish ++;
			SafeInfo(work,r);
			safeSeries[safeIndex] = r;
			safeIndex ++;
			Finish[r] = true;
		}
		r ++;//該式必須在此處	
		if(r >= processNum)
		{
			r = r % processNum;
			if(temp == allFinish)
			{
				break;	
			}
			temp = allFinish;
		}		
		pNum = allFinish;
	}	
	//判斷系統是否安全
	for(i = 0; i < processNum; i++)
	{
		if(Finish[i] == false)
		{
			printf("\n當前系統不安全!\n\n");
			return false;	
		}
	}
	//打印安全序列
	printf("\n當前系統安全!\n\n安全序列爲:");
	for(i = 0; i < processNum; i++)
	{	
		bool result = isAllZero(i);
		if(result == true)
		{		
			pNum --;
		}	
	}
	for(i = 0; i < pNum; i++)
	{
		printf("%d ",safeSeries[i]);
	}
	return true;
}

//主函數
void main()
{
	int curProcess = 0;
	int a = -1;
	showInfo(); 
	printf("\n系統安全情況分析\n");
	printf(" PID\t Work\t\tAllocation\t Need\t\tWork+Allocation\n");
	bool isStart = isSafe();
	//用戶輸入或者預設系統資源分配合理才能繼續進行進程分配工作
	while(isStart)
	{
		//限制用戶輸入,以防用戶輸入大於進程數量的數字,以及輸入其他字符(亂輸是不允許的)
		do
		{ 
			if(curProcess >= processNum || a == 0)
			{
				printf("\n請不要輸入超出進程數量的值或者其他字符:\n");
				while(getchar() != '\n'){};//清空緩衝區	
				a = -1;
			}
			printf("\n------------------------------------------------------------------------------------\n");
			printf("\n輸入要分配的進程:");
			a = scanf("%d",&curProcess);
			printf("\n");

		}while(curProcess >= processNum || a == 0);

		//限制用戶輸入,此處只接受數字,以防用戶輸入其他字符(亂輸是不允許的)
		for(int i = 0; i < resourceNum; i++)
		{
			do
			{
				if(a == 0)
				{
					printf("\n請不要輸入除數字以外的其他字符,請重新輸入:\n");
					while(getchar() != '\n'){};//清空緩衝區	
					a = -1;
				}
				printf("請輸入要分配給進程 P%d 的第 %d 類資源:",curProcess,i+1);
				a = scanf("%d", &request[i]);
			}while( a == 0);
		}

		//判斷用戶輸入的分配是否合理,如果合理,開始進行預分配
		num  = 0;
		for(i = 0; i < resourceNum; i++)
		{
			if(request[i] <= need[curProcess][i] && request[i] <= available[i])
			{
				num ++;
			}
			else
			{
				printf("\n發生錯誤!可能原因如下:\n(1)您請求分配的資源可能大於該進程的某些資源的最大需要!\n(2)系統所剩的資源已經不足了!\n");
				break;
			}
		}
		if(num == resourceNum)
		{	
			num = 0;	
			for(int j = 0; j < resourceNum; j++)
			{
				//分配資源
				available[j] = available[j] - request[j];
				allocation[curProcess][j] = allocation[curProcess][j] + request[j];
				need[curProcess][j] = need[curProcess][j] - request[j];
				//記錄分配以後,是否該進程需要值爲0了
				if(need[curProcess][j] == 0)
				{
					num ++;
				}
			}
			//如果分配以後出現該進程對所有資源的需求爲0了,即刻釋放該進程佔用資源(視爲完成)
			if(num == resourceNum)
			{
				//釋放已完成資源
				for(int i = 0; i < resourceNum; i++ )
				{
					available[i] = available[i] + allocation[curProcess][i];
				}
				printf("\n\n本次分配進程 P%d 完成,該進程佔用資源全部釋放完畢!\n",curProcess);
			}
			else
			{
				//資源分配可以不用一次性滿足進程需求
				printf("\n\n本次分配進程 P%d 未完成!\n",curProcess);
			}

			showInfo();
			printf("\n系統安全情況分析\n");
			printf(" PID\t Work\t\tAllocation\t Need\t\tWork+Allocation\n");

			//預分配完成以後,判斷該系統是否安全,若安全,則可繼續進行分配,若不安全,將已經分配的資源換回來
			if(!isSafe())
			{ 	        
				for(int j = 0; j < resourceNum; j++)
				{
					available[j] = available[j] + request[j];
					allocation[curProcess][j] = allocation[curProcess][j] - request[j];
					need[curProcess][j] = need[curProcess][j] +request[j];
				}
				printf("資源不足,等待中...\n\n分配失敗!\n");				
			}
		}
	}
}

計算機操作系統_銀行家算法

3.銀行家算法是否實用

首先,我們寫的時候mutex鎖問題肯定是不太實用的,那操作系統實用這種方式來分配資源嗎?我覺得不太合適(不缺的,只是結合網上的資料我覺得)原因有如下幾條:

  1. 這個算法要求客戶數保持固定不變,這在多道程序系統中是難以做到的。
  2. 這個算法保證所有客戶在有限的時間內得到滿足,但實時客戶要求快速響應,所以要考慮這個因素。
  3. 由於要尋找一個安全序列,實際上增加了系統的開銷

除此之外我還看到了一篇網友對此討論的文章,說的是操作系統內核使用的是這種方式嗎?雖然都是一堆沒看過源碼的人說的,但是結論也是不實用《在實際的OS中,資源分配是用"銀行家算法"嗎

99.參考的文章

https://blog.csdn.net/ZWE7616175/article/details/80201520

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章