一.死鎖的概念
在多道程序系統中,雖可藉助於多個進程的併發執行,來改善系統的資源利用率,提高系統的吞吐量,但可能發生一種危險━━死鎖。所謂死鎖(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序列。