1. 程式人生 > >死鎖產生的原因以及避免死鎖的演算法

死鎖產生的原因以及避免死鎖的演算法

一.死鎖的概念

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