程序管理之死鎖

2021-06-19 22:50:12 字數 3835 閱讀 4116

前面兩篇部落格

1.程序同步之臨界區域問題及peterson演算法

2.程序同步之訊號量機制(pv操作)及三個經典同步問題

介紹了程序管理中程序同步的諸多問題,下面為大家詳細解讀程序管理中死鎖的問題及其解決方案。

在多道程式設計環境下,多個程序可能競爭一定數量的資源。乙個程序申請資源,如果資源不可用,那麼進入等待狀態。如果所申請的資源被其他等待程序占有,那麼該等待程序有可能無法改變狀態,這種情況稱為死鎖(deadlock) 。

設系統有一台印表機(r1),一台讀卡機(r2),兩程序共享這兩台裝置。

用訊號量s1表示r1是否可用,初值為1;

用訊號量s2表示r2是否可用,初值為1;

這兩個程序在併發執行過程中,可能會發生如下的情況。

即p1占用r1,p2占用r2,同時p1和p2又分別申請r2和r1的資源。於是造成了死鎖。

大家可以思考一下,如何修改a、b程序才不會發生死鎖。帶著這個問題我們往下看。

如迴圈圖所示:

系統中只有一台印表機r1和一台讀卡機r2,可供程序p1和p2共享。r1、r2已經分別分配給p1、p2使用,當p1、p2在不釋放資源r1、r2而又同時分別申請r2、r1(如圖),形成環路,這樣會產生死鎖。

如前面的例子可知他只是可能發生死鎖,也就是說程序的推進不同會導致不同的結果。

互斥條件

程序要求對所分配的資源進行排它性控制,即在一段時間內某資源僅為一程序所占用。

占有並等待條件

當程序因請求資源而阻塞時,對已獲得的資源保持不放。

非搶占條件

程序已獲得的資源在未使用完之前,不能剝奪,只能在使用完時由自己釋放。

迴圈等待條件

在發生死鎖時,必然存在乙個程序--資源的環形鏈。

前面我們降到了死鎖的必要條件,那麼只要乙個條件不滿足的話,就不會發生死鎖了。所以我們可以從必要條件的角度來預防死鎖。

a.互斥條件

對於非共享資源,必須有互斥條件。而共享資源是不會涉及死鎖。所以通常不能通過否定互斥條件來預防死鎖:有些資源本身是非共享的。

b.占有並等待

為了確保該條件不在系統內出現,必須保證:當乙個程序申請乙個資源時,它不能占有其他資源。

資源一次性分配

可以解決這個問題。實現這一分配有兩種協議

1.每個程序在執行前申請並獲得所有資源。

2.允許程序在沒有資源時才可申請資源。

兩種協議的缺點:

1.資源利用率不高

2.可能發生飢餓(磁帶用到一般被搶了)

c.非搶占

允許當前程序被其他程序搶過去。

缺點:可能發生飢餓(磁帶用到一般被搶了)

d.迴圈等待條件

確保此條件不成立的方法就是對所有資源型別進行完全排序,且要求每個程序按遞增順序來申請資源。

實現方法:資源有序分配法

遵循兩種協議:

1.每個程序只按遞增順序申請資源。(第一次可以申請多個,但之後申請編號必須比前面大)

2.程序申請編號比擁有資源編號小時必須先釋放大編號資源。

這樣程序如果需要磁帶機和繪圖機,那程序必須先申請磁帶機,再申請繪圖機。如果再想申請印表機,則必須先釋放繪圖機。

通過前面介紹想必大家也看到了在預防死鎖的過程中會嚴重系統效能。因此在避免死鎖中我們不得不施加較弱的限制,從而獲得比較滿意的效能。

由於在避免死鎖的策略中,允許程序動態地申請資源。因而,系統在進行資源分配之前預先計算 資源分配的安全性。若此次分配不會導致系統進入不安全狀態,則將資源分配給程序;否則,程序等待。

最具代表性的避免死鎖的演算法是銀行家演算法。由於銀行家演算法比較複雜,我將在下篇部落格中詳細解讀。

一般來說,由於作業系統有併發,共享以及隨機性等特點,通過預防和避免的手段達到排除死鎖的目的是很困難的。這需要較大的系統開銷,而且不能充分利用資源。

為此,一種簡便的方法是系統為程序分配資源時,不採取任何限制性措施,但是提供了檢測和解脫死鎖的手段:能發現死鎖並從死鎖狀態中恢復出來。

因此,在實際的作業系統中往往採用死鎖的檢測與恢復方法來排除死鎖。 死鎖檢測與恢復是指系統設有專門的機構,當死鎖發生時,該機構能夠檢測到死鎖發生的位置和原因,並能通過外力破壞死鎖發生的必要條件,從而使得併發程序從死鎖狀態中恢復出來。

1.乙個用來檢查系統狀態從而確定是否出現了死鎖演算法。即死鎖檢測

2.乙個用來從死鎖狀態中恢復的演算法。即恢復演算法

首先可以通過畫分配圖來判斷是否發生了死鎖。但如何用演算法來判斷呢?

死鎖檢測演算法。演算法使用的資料結構是如下這些:      

占有矩陣a:n*m階,其中n表示併發程序的個數,m表示系統的各類資源的個數,這個矩陣記錄了每乙個程序當前占有各個資源類中資源的個數。

申請矩陣r:n*m階,其中n表示併發程序的個數,m表示系統的各類資源的個數,這個矩陣記錄了每乙個程序當前要完成工作需要申請的各個資源類中資源的個數。

空閒向量t:記錄當前m個資源類中空閒資源的個數。

完成向量f:布林型向量值為真(true)或假(false),記錄當前n個併發程序能否進行完。為真即能進行完,為假則不能進行完。

臨時向量w:開始時w:=t。

演算法步驟:

(1)w:=t,

對於所有的i=1,2,...,n,

如果a[i]=0,則f[i]:=true;否則,f[i]:=false

(2)找滿足下面條件的下標i:

f[i]:=false並且r[i]〈=w

如果不存在滿足上面的條件i,則轉到步驟(4)。

(3)w:=w+a[i]

f[i]:=true

轉到步驟(2)

(4)如果存在i,f[i]:=false,則系統處於死鎖狀態,且pi程序參與了死鎖。什麼時候進行死鎖的檢測取決於死鎖發生的頻率。如果死鎖發生的頻率高,那麼死鎖檢測的頻率也要相應提高,這樣一方面可以提高系統資源的利用率,一方面可以避免更多的程序捲入死鎖。如果程序申請資源不能滿足就立刻進行檢測,那麼每當死鎖形成時即能被發現,這和死鎖避免的演算法相近,只是系統的開銷較大。為了減小死鎖檢測帶來的系統開銷,一般採取每隔一段時間進行一次死鎖檢測,或者在cpu的利用率降低到某一數值時,進行死鎖的檢測。 

一旦在死鎖檢測時發現了死鎖,就要消除死鎖,使系統從死鎖狀態中恢復過來。  

(1)最簡單,最常用的方法就是進行系統的重新啟動,不過這種方法代價很大,它意味著在這之前所有的程序已經完成的計算工作都將付之東流,包括參與死鎖的那些程序,以及未參與死鎖的程序。

(2)撤消程序,剝奪資源。終止參與死鎖的程序,收回它們占有的資源,從而解除死鎖。這時又分兩種情況:一次性撤消參與死鎖的全部程序,剝奪全部資源;或者逐步撤消參與死鎖的程序,逐步收回死鎖程序占有的資源。一般來說,選擇逐步撤消的程序時要按照一定的原則進行,目的是撤消那些代價最小的程序,比如按程序的優先順序確定程序的代價;考慮程序執行時的代價和與此程序相關的外部作業的代價等因素。 

此外,還有程序回退策略,即讓參與死鎖的程序回退到沒有發生死鎖前某一點處,並由此點處繼續執行,以求再次執行時不再發生死鎖。雖然這是個較理想的辦法,但是操作起來系統開銷極大,要有堆疊這樣的機構記錄程序的每一步變化,以便今後的回退,有時這是無法做到的。

執行緒同步之死鎖

public class stateobject i public void deadlock2 i stateobject state1 new stateobject stateobject state2 new stateobject new thread new samplethread s...

執行緒同步之死鎖

什麼是死鎖呢?死鎖就是多個程序或者執行緒訪問同乙個資源的時候,誰也搶不到資源,誰也不退讓讓其他程序或者執行緒訪問,使用者看到的就是程式卡住了。舉個例子吧,在乙個沒有紅綠燈的十字路口,來了四輛小汽車,每個路口都只能讓乙個汽車通過。現在這種情況四輛車都過不了汽車,這就發生了死鎖。發生死鎖的原因?第一種情...

PostgreSQL之死鎖模擬

1.什麼是死鎖 多個程序競爭資源,a程序占用了一部分資源,又去申請其他資源,a程序申請的資源被b程序占用,b程序申請a資源占用的資源,這樣就形成了死鎖。2.產生死鎖的條件是什麼 1 互斥 2 占有並等待 3 非剝奪 4 迴圈等待 3.解決死鎖的方法 1 預防死鎖 通過破壞死鎖產生的條件一致 效率低 ...