死鎖產生的原因以及避免死鎖的演算法
一.死鎖的概念
在多道程式系統中,雖可藉助於多個程序的併發執行,來改善系統的資源利用率,提高系統的吞吐量,但可能發生一種危險━━死鎖。所謂死鎖(Deadlock),是指多個程序在執行中因爭奪資源而造成的一種僵局(Deadly_Embrace),當程序處於這種僵持狀態時,若無外力作用,它們都將無法再向前推進。一組程序中,每個程序都無限等待被該組程序中另一程序所佔有的資源,因而永遠無法得到的資源,這種現象稱為程序死鎖,這一組程序就稱為死鎖程序。
二.死鎖產生的原因
產生死鎖的原因主要是:
(1) 因為系統資源不足。
(2) 程序執行推進的順序不合適。
(3) 資源分配不當等。
如果系統資源充足,程序的資源請求都能夠得到滿足,死鎖出現的可能性就很低,否則就會因爭奪有限的資源而陷入死鎖。其次,程序執行推進順序與速度不同,也可能產生死鎖。產生死鎖的四個必要條件:
(1) 互斥條件:一個資源每次只能被一個程序使用。
(2) 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:程序已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
- 死鎖的解除與預防:
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、程序排程等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配演算法,避免程序永久佔據系統資源。此外,也要防止程序在處於等待狀態的情況下佔用資源。因此,對資源的分配要給予合理的規劃。
二.資料結構設計
(一)可利用資源向量矩陣AVAILABLE。這是一個含有m個元素的陣列,其中的每一個元素代表一類可利用的資源數目,其初始值是系統中所配置的該類全部可用資源的數目,其數值隨該類資源的分配和回收而動態地改變。如果AVAILABLE [j]= K,則表示系統中現有R類資源K個
(二)最大需求矩陣MAX。這是一個n*m的矩陣,用以表示每一個程序對m類資源的最大需求。如果MAX =K,則表示程序i需要R類資源的數目為K。
(三)分配矩陣ALLOCATION。這也是一個n*m的矩陣,它定義了系統中每一類資源當前已分配給每一程序的資源數。如果ALLOCATION =K,則表示程序i當前已分得R類資源的數目為K。 (四)需求矩陣NEED。這也是一個n*m的矩陣,用以表示每一個程序尚需的各類資源數。如果NEED =K,則表示程序i還需要R類資源K個,才能完成其任務。 上述矩陣存在下述關係: NEED = MAX-ALLOCATION
三.演算法實現
(一) 初始化 由使用者輸入資料,分別對可利用資源向量矩陣AVAILABLE、最大需求矩陣MAX、分配矩陣ALLOCATION、需求矩陣NEED賦值。
(二)銀行家演算法 在避免死鎖的方法中,所施加的限制條件較弱,有可能獲得令人滿意的系統性能。在該方法中把系統的狀態分為安全狀態和不安全狀態,只要能使系統始終都處於安全狀態,便可以避免發生死鎖。 銀行家演算法的基本思想是分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死鎖的演算法。 設程序cusneed提出請求REQUEST ,則銀行家演算法按如下規則進行判斷。
(1)如果REQUEST [cusneed] <= NEED[cusneed],則轉(2);否則,出錯。
(2)如果REQUEST [cusneed] <= AVAILABLE[cusneed],則轉(3);否則,出錯。 (3)系統試探分配資源,修改相關資料:
AVAILABLE-=REQUEST[cusneed]; ALLOCATION[cusneed]+=REQUEST[cusneed];
NEED[cusneed]-=REQUEST[cusneed];
(4)系統執行安全性檢查,如安全,則分配成立;否則試探險性分配作廢,系統恢復原狀,程序等待。
(三)安全性檢查演算法
(1)設定兩個工作向量Work=AVAILABLE;FINISH
(2)從程序集合中找到一個滿足下述條件的程序,
FINISH==false;
NEED<=Work;
如找到,執行(3);否則,執行(4)
(3)設程序獲得資源,可順利執行,直至完成,從而釋放資源。 Work+=ALLOCATION; Finish=true; GOTO 2
(4)如所有的程序Finish= true,則表示安全;否則系統不安全。
四.源程式清單
#include <iostream> using namespace std;
#define MAXPROCESS 50 /*最大程序數*/
#define MAXRESOURCE 100 /*最大資源數*/
int AVAILABLE[MAXRESOURCE]; /*可用資源陣列*/
int MAX[MAXPROCESS][MAXRESOURCE]; /*最大需求矩陣*/
int ALLOCATION[MAXPROCESS][MAXRESOURCE]; /*分配矩陣*/
int NEED[MAXPROCESS][MAXRESOURCE]; /*需求矩陣*/
int REQUEST[MAXPROCESS][MAXRESOURCE]; /*程序需要資源數*/
bool FINISH[MAXPROCESS]; /*系統是否有足夠的資源分配*/
int p[MAXPROCESS]; /*記錄序列*/
int m,n; /*m個程序,n個資源*/ void Init(); bool Safe(); void Bank(); int main()
{
Init();
Safe();
Bank();
}
void Init() /*初始化演算法*/
{
int i,j;
cout<<"請輸入程序的數目:";
cin>>m;
cout<<"請輸入資源的種類:";
cin>>n;
cout<<"請輸入每個程序最多所需的各資源數,按照"<<m<<"x"<<n<<"矩陣輸入"<<endl;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
cin>>MAX[j];
cout<<"請輸入每個程序已分配的各資源數,也按照"<<m<<"x"<<n<<"矩陣輸入"<<endl; for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
cin>>ALLOCATION[j];
NEED[j]=MAX[j]-ALLOCATION[j];
if(NEED[j]<0)
{
cout<<"您輸入的第"<<i+1<<"個程序所擁有的第"<<j+1<<"個資源數錯誤,請重新輸入:"<<endl;
j--;
continue;
}
}
}
cout<<"請輸入各個資源現有的數目:"<<endl;
for(i=0;i<n;i++)
{
cin>>AVAILABLE;
}
}
void Bank() /*銀行家演算法*/
{
int i,cusneed;
char again;
while(1)
{
cout<<"請輸入要申請資源的程序號(注:第1個程序號為0,依次類推)"<<endl;
cin>>cusneed;
cout<<"請輸入程序所請求的各資源的數量"<<endl;
for(i=0;i<n;i++)
{
cin>>REQUEST[cusneed];
}
for(i=0;i<n;i++)
{
if(REQUEST[cusneed]>NEED[cusneed])
{
cout<<"您輸入的請求數超過程序的需求量!請重新輸入!"<<endl;
continue;
}
if(REQUEST[cusneed]>AVAILABLE)
{
cout<<"您輸入的請求數超過系統有的資源數!請重新輸入!"<<endl;
continue;
}
}
for(i=0;i<n;i++)
{
AVAILABLE-=REQUEST[cusneed];
ALLOCATION[cusneed]+=REQUEST[cusneed];
NEED[cusneed]-=REQUEST[cusneed];
}
if(Safe())
{
cout<<"同意分配請求!"<<endl;
}
else
{
cout<<"您的請求被拒絕!"<<endl;
for(i=0;i<n;i++)
{
AVAILABLE+=REQUEST[cusneed];
ALLOCATION[cusneed]-=REQUEST[cusneed];
NEED[cusneed]+=REQUEST[cusneed];
}
}
for(i=0;i<m;i++)
{
FINISH=false;
}
cout<<"您還想再次請求分配嗎?是請按y/Y,否請按其它鍵"<<endl;
cin>>again;
if(again=='y'||again=='Y')
{
continue;
}
break;
}
}
bool Safe()/*安全性演算法*/
{
int i,j,k,l=0;
int Work[MAXRESOURCE];/*工作陣列*/
for(i=0;i<n;i++)
Work=AVAILABLE;
for(i=0;i<m;i++)
{
FINISH=false;
}
for(i=0;i<m;i++)
{
if(FINISH==true)
{
continue;
}
else
{
for(j=0;j<n;j++)
{
if(NEED[j]>Work[j])
{
break;
}
}
if(j==n)
{
FINISH=true;
for(k=0;k<n;k++)
{
Work[k]+=ALLOCATION[k];
}
p[l++]=i;
i=-1;
}
else
{
continue;
}
}
if(l==m)
{
cout<<"系統是安全的"<<endl;
cout<<"安全序列:"<<endl;
for(i=0;i<l;i++)
{
cout<<p;
if(i!=l-1)
{
cout<<"-->";
}
}
cout<<""<<endl;
return true;
}
}
cout<<"系統是不安全的"<<endl;
return false;
}
五.實驗分析:
(1)下列狀態是否安全?(三個程序共享12個同類資源) 程序 已分配資源數 最大需求數
1 1 4 (狀態a)
2 4 4
3 5 8
1 1 4 (狀態b)
2 4 6
3 6 8
狀態a安全,序列為:2–>1–> 3
狀態b不安全,只剩1個可用資源,收不回已分配資源。
(2)考慮下列系統狀態
分配矩陣 | 最大需求矩陣 | 可用資源矩陣 |
---|---|---|
0 0 1 2 | 0 0 1 2 | 1 5 2 0 |
1 0 0 0 | 1 7 5 0 | |
1 3 5 4 | 2 3 5 6 | |
0 6 3 2 | 0 6 5 2 | |
0 0 1 4 | 0 6 5 6 |
問系統是否安全?若安全就給出所有的安全序列。若程序2請求(0420),可否立即分配?
答:安全。安全序列為:1–>3–>2–>5–>4。 若程序2請求(0420),可立即分配。分配後可用資源為1 1 0 0,回收1程序資源, 可用資源數為:1 1 1 2,然後執行3–>2–>5–>4序列。