1. 程式人生 > >死鎖 銀行家演算法

死鎖 銀行家演算法

產生死鎖的原因可歸結為如下兩點:
競爭資源。系統中供多個程序共享的資源如印表機、公用佇列等的數目不滿足需要時,會引起資源競爭而產生死鎖。
程序間推進順序非法。程序在執行過程中,請求和釋放資源的順序不當,同樣會導致死鎖。
產生死鎖的必要條件:
形成死鎖的四個必要條件(四個條件都具備就會死鎖,缺一就不會死鎖)
1.互斥條件:程序對所分配到的資源進行排他性使用
2.請求和保持條件:程序已經保持了至少一個資源,又提出新的資源請求,而新請求資源被其他程序佔有只能造成自身程序阻塞,但對自己已獲得的其他資源保持不放,必然影響其他程序。
3.不剝奪條件:程序已獲得的資源未使用完之前不能被剝奪,只能在使用完時由自己釋放。
4.環路等待條件
處理死鎖的基本方法:
1.預防死鎖
設定限制條件,破壞四個必要條件的一個或幾個,預防發生死鎖。
較易實現。限制條件的嚴格也會導致系統資源利用率和系統吞吐量降低。
2.避免死鎖
不須事先限制,破壞四個必要條件,而是在資源的動態分配過程中,用某種方法去防止系統進入不安全狀態,從而避免發生死鎖。
這種事先加以較弱限制的方法,實現上有一定難度,但可獲較高的資源利用率及系統吞吐量,目前在較完善的系統中,常用此方法來避免發生死鎖。
3.檢測死鎖。
允許系統執行過程中發生死鎖,但通過系統檢測機構可及時的檢測出,能精確確定與死鎖有關的程序和資源;然後採取適當的措施,從系統中將已發生的死鎖清除掉。
4.解除死鎖。
與死鎖檢測配套的一種措施。
常用的實施方法:撤銷或掛起一些程序,以便回收一些資源並將他們分配給已阻塞程序,使之轉為就緒以繼續執行。
死鎖的檢測與解除措施,有可能使系統獲得較好的資源利用率和吞吐量(死鎖機率不一定很高),但在實現上難度也最大。

預防死鎖
資源的排他性無法更改,故在其他3個條件上入手
摒棄“請求和保持”條件:所有程序開始執行前,必須一次性的申請其在整個執行過程所需的全部資源(AND)。演算法簡單、易於實現且很安全。但缺點是資源浪費嚴重、或程序延遲執行。
摒棄“不剝奪”條件:允許程序先執行,但當提出的新要求不被滿足時必須釋放它已保持的所有資源,待以後需要時再重新申請。實現比較複雜且付出很大代價。可能會造成前功盡棄,反覆申請和釋放等情況。
摒棄“環路等待”條件
有序設定資源:將所有資源按型別進行線性排隊,賦予不同序號。所有程序對資源的請求必須嚴格按照資源序號遞增的次序提出,這樣在所形成的資源分配圖中,不可能會出現環路。
避免死鎖
銀行家演算法避免死鎖
【思路描述】:隨時對系統中的所有資源資訊進行統計,包括每種資源的數量、已分配給各程序的數量;每當程序提出某種資源請求時判斷該請求分配後是否安全,如果安全才分配。對每個資源請求的處理都要保證系統始終從一個安全狀態到另一個安全狀態。
演算法實現說明:
首先:需要的一些資料結構
再次:演算法過程
核心:安全性判斷演算法

m類資源,n個併發程序對其產生需求
1)銀行家演算法中的資料結構
(1)各類可利用資源的數量
向量Available :(i1,i2,…,im),含m個元素,每個元素代表一類可利用的資源數目。
動態變化的,初始值是系統配置的該類資源的全部數目,值隨資源的分配與回收而動態的改變。
實現:一維陣列。Available【j】=K,表示系統中Rj類資源現有可用數量為K個。
(2)每個程序對每類資源的需求
最大需求、已獲得的、還需要的
最大需求矩陣Max
nm,系統中n個程序中每個程序分別對m類資源的最大需求。
取值:根據程序需求賦初始值。
實現:二維陣列。Max【i,j】=K,表示程序 i 需要Rj類資源的最大數目為K。
已分配矩陣Allocation。
n

m,定義系統中每一程序已獲得的每類資源數量。
Allocation【i,j】=K,表示程序i當前已分得Rj類資源數為K。
還需求的矩陣Need。
n*m,表示每一程序尚需的各類資源數。
Need【i,j】=K,表示程序i還需要Rj類資源K個,方能完成任務。
上述三個矩陣存在關係:
Max【i,j】= Allocation【i,j】+Need【i,j】
每次,給程序 i 分配資源的動作,影響上述資料結構的取值:
Available【  】,Allocation【i,】,Need【i,】
2)避免死鎖的演算法過程(銀行家演算法)
當前資源分配狀態如何?構建資源分配表
判斷向下執行過程中,各程序對資源的需求是否安全。
在當前資源分配狀態基礎上,分析程序的實際請求Requesti【j】= k。表示程序Pi需要K個Rj型別的資源。
程序Pi發出資源請求後,系統按下述步驟進行檢查:
首先是兩個基本判斷:
(1)IF Requesti[j]<= Need[i,j]
THEN 轉向步驟2;
ELSE 認為出錯,所需資源數超過宣佈的最大值(自我矛盾)
(2)IF Requesti[j]<= Available[j]
THEN 轉向步驟3;
ELSE 表示尚無足夠資源,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)系統執行安全性演算法,判斷新的資源分配狀態是否是安全的。
即:找一個安全序列,使這些程序按順序執行完)如果能夠找到,則將假設操作真正實施完成資源分配。
3)安全性演算法
1)需要一些記錄資訊的資料結構,設定兩個向量:
工作向量work
演算法開始時work=Available;
系統找安全序列的過程需要不斷判斷和修改當前資源數量,不能直接修改原始資料記錄Aailable。
標誌向量Finish
表示每個程序是否有足夠的資源使之執行完成。開始時所以程序都設定初值Finish[i]:=false;
找安全序列的過程相當於使所有Finish[i]:=true。
(2)找安全序列的過程
從 Finish[i] = false 的程序集合中找一個程序
IF Need[i,j] <= work[j]
THEN 執行步驟 a;
ELSE 執行步驟 b;
a) 假設Pi獲得資源順利執行完,釋放出分配給它的資源,修改相應的值:
work【j】 = work【i】+ Allocation【i,j】;
Finish【i】= true;
goto step (2); //返回去繼續找下一個程序。
b)當演算法不再在(2)、a)步間迴圈找程序,到達本步時,若所有Finish[i]=true都滿足,則表示所有程序都按某個順序執行完了,系統處於安全狀態;否則,系統當前所處的資源分配狀態是不安全狀態。