死結是指兩個或兩個以上的進程在執行的過程中,因爭奪資源而造成的一種互相等待的現象。
產生死結的四個必要條件:
1、互斥條件:一個資源每次只能被一個進程使用。
2、請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。(資源的部分分配)
3、不剝奪條件:進程已經獲得的資源,在未使用完之前,不能強行剝奪。
4、迴圈等待條件:若干進程之間形成一種頭尾相接的迴圈等待資源關係。
上述四個條件是產生死結的四個必要條件,只要上述四個之中有一個不滿足,就不會發生死結。
根據上述條件,列出三條預防措施:
1、採用資源靜態分配的策略,破壞“部分分配”條件。
2、允許進程剝奪使用其他進程佔有的資源,從而破壞“不可剝奪”條件。
3、採用資源有序分配方法,破壞“環路”條件。
注意:互斥條件沒法被破壞。
死結避免演算法裡最著名的演算法就是Dijkstra的銀行家演算法。
銀行家演算法:
基本思想是分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死結的演算法。
設進程cusneed提出請求REQUEST [i],則銀行家演算法按如下規則進行判斷。
(1)如果REQUEST [cusneed] [i]<= NEED[cusneed][i],則轉(2);否則,出錯。
(2)如果REQUEST [cusneed] [i]<= AVAILABLE[cusneed][i],則轉(3);否則,出錯。
(3)系統試探分配資源,修改相關資料:
AVAILABLE[i]-=REQUEST[cusneed][i];
ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];
NEED[cusneed][i]-=REQUEST[cusneed][i];
(4)系統執行安全性檢查,如安全,則分配成立;否則試探險性分配作廢,系統復原原狀,進程等待。
安全性檢查演算法:
(1)設定兩個工作向量Work=AVAILABLE; FINISH(全為false)
(2)從進程集合中找到一個滿足下述條件的進程,
FINISH==false;
NEED<=Work;
如找到,執行(3);否則,執行(4)
(3)設進程獲得資源,可順利執行,直至完成,從而釋放資源。
Work+=ALLOCATION;
Finish=true;
GOTO(2)
(4)如所有的進程Finish= true,則表示安全;否則系統不安全。
銀行家演算法的代碼執行個體:
#include<stdio.h>#include<stdlib.h>#include<string.h>#define N 5 //進程個數#define M 3 //資源種類int main(){int i,j;int a;int Request[M];//請求資源距陣int Allocation[N][M];//已經分配資源矩陣int Need[N][M];//需求矩陣int Available[M];//可利用資源量//輸入已經分配的資源printf("請輸入已經分配的資源:\n");for(i=0;i<N;i++){printf("請輸入第 %d 個進程已經分配的資源:",i+1);for(j=0;j<M;j++)scanf("%d",&Allocation[i][j]);}//輸入各個進程還需要的資源printf("\n請輸入各個進程還需要的資源:\n");for(i=0;i<N;i++){printf("請輸入第 %d 個進程還需要的資源:",i+1);for(j=0;j<M;j++)scanf("%d",&Need[i][j]);}//輸入可以利用的資源資料printf("\n請輸入可以利用的資源資料:");for(i=0;i<M;i++)scanf("%d",&Available[i]);while(1){ start:printf("\n\n請輸入是第幾個進程發出資源請求:");scanf("%d",&a);//輸入的是第幾個進程的請求printf("\n第 %d 個進程資源請求數:",a);for(i=0;i<M;i++)scanf("%d",&Request[i]);//銀行家演算法第一步for(i=0;i<M;i++){if(!(Request[i]<=Need[a-1][i])){printf("P%d 非法請求!",a);printf("不可以分配給 P%d 進程!",a);goto start;}}//銀行家演算法第二步for(i=0;i<M;i++){if(!(Request[i]<=Available[i])){printf("P%d 進程阻塞!",a);printf("不可以分配給 P%d 進程!",a);goto start;}}//銀行家演算法第三步:試探性分配for(i=0;i<M;i++){Available[i]=Available[i]-Request[i];Allocation[a-1][i]=Allocation[a-1][i]+Request[i];Need[a-1][i]=Need[a-1][i]-Request[i];}//銀行家演算法第四步:安全性檢查int Finish[N]={0,0,0,0,0};int Work[M];for(i=0;i<M;i++)Work[i]=Available[i];int flag=1;while(flag==1){for(i=0;i<N;i++){for(j=0;j<M;j++){if(Finish[i]==0 && Need[i][j]<=Work[j]){if(j==M-1){Finish[i]=1;printf("\nP%d 進程安全性檢查通過",i+1);for(j=0;j<M;j++)Work[j]=Work[j]+Allocation[i][j];}}continue;}}int sum=0;for(i=0;i<N;i++)sum=sum+Finish[i];if(sum==5)flag=0;}for(i=0;i<N;i++){if(Finish[i]==0){printf("試探性分配不成功!安全性檢查不通過!");printf("\n不可以分配給 P%d 進程!",a);Available[i]=Available[i]+Request[i];Allocation[a-1][i]=Allocation[a-1][i]-Request[i];Need[a-1][i]=Need[a-1][i]+Request[i];goto start;}}printf("\n\n安全!可以分配給 P%d 進程!\n",a);//輸出分配成功後資源佔有、需求和可利用情況printf("\n資源佔有情況:\n");for(i=0;i<N;i++){printf("P%d 個進程已經分配的資源:",i+1);for(j=0;j<M;j++)printf(" %d ",Allocation[i][j]);printf("\n");}printf("\n資源需求情況:\n");for(i=0;i<N;i++){printf("P%d 個進程還需要的資源:",i+1);for(j=0;j<M;j++)printf(" %d ",Need[i][j]);printf("\n");}printf("\n可以利用的資源資料:");for(i=0;i<M;i++)printf(" %d ",Available[i]);printf("\n");}return 0;}