一、死鎖概述
1.1 什麼是死鎖
如果一個進程集合中的每隔進程都在等待只能由該進程集合中的其他進程才能引發的事件,那麼,該進程就是死鎖的。
在大多數情況下,每個進程等待的事件是釋放該進程集合中其他進程所佔有的資源。比如:A 在等 B 釋放資源才能運行完成,而 B 在等 A 釋放資源才能完成,這就產生了死鎖。
1.2 死鎖產生的條件
- 互斥:每個資源要麼已經分配給了一個進程,要麼就是可用的(即不可以同時分配給多個進程)。
- 佔有並等待:已經得到某個資源的進程還在等待其他資源纔可以繼續運行。
- 不可搶佔:已經分配給一個進程的資源不能強佔性地被搶佔,只能等佔有它的進程顯示地釋放。
- 循環等待:死鎖發生時,系統中一定有兩個或兩個以上的進程組成的一條環路,該環路中的每個進程都在等待着下一個進程所佔有的資源。
如果死鎖發生,那麼這四個條件一定同時滿足, 但這四個條件同時滿足,死鎖不一定發生。
1.3 死鎖建模
R:資源類型,每一個類型中可能有多個資源;
P:進程;
R -> P:資源分配給了進程;
P -> R:進程等待資源
(下面着三個圖就很好地解釋了 1.2 中的概念)
二、解決死鎖問題
2.1 鴕鳥算法
鴕鳥算法就是不去處理死鎖,假設死鎖永遠不會產生,如果產生的話,就重啓系統。這是最直接也是做常用的算法,因爲在實際開發中,死鎖產生的頻率並不高,如果時刻都處理死鎖的話,會降低系統性能。
2.2 死鎖預防
在 1.2 中提到了死鎖如果產生,互斥、非搶佔、佔有並等待、循環等待這四個條件一定會同時滿足,如果我們是一種條件不被滿足,死鎖就不會產生:
-
破壞互斥:一個資源同時讓多個進程使用(不太現實)
-
破壞非搶佔:一個進程在請求資源時,把佔有該資源的進程 kill 掉(也不太常用)
-
破壞佔有並等待:禁止已持有資源的進程再等待其他資源。兩種策略:
Ⅰ. 進程在啓動時就把它需要的資源全部獲取到,這樣的方式存在兩個問題:一個是很多進程只有在運行時才知道自己需要多少資源,另一個問題是提前獲取所有資源但是隻使用其中的一部分,就會造成資源浪費。
Ⅱ. 當一個進程請求資源時,先暫時釋放當前佔用的所有資源,然後再嘗試一次獲得所需的全部資源。
-
破壞循環等待:把所有的資源進行排序,要求進程按照資源的順序進行申請。如果已經 A 佔有資源 i,i <j , 則 A 現在不能申請資源 j,只有把 i 釋放,才能申請 j 。
2.3 死鎖避免
如果進程集合中有一個執行序列可以滿足所有進程都能順利執行完,則該進程集合中不存在死鎖。死鎖避免採用銀行家算法:
標識符:
-max[m] [n] :進程 m 需要資源 n 的最大數量
-allocated[m] [n]:進程 m 已經得到資源 n 的數量
-need[m] [n]:進程 m 還需要資源 n 的數量
-max = allocated + need
-available[n]:資源 n 現在還有的數量
尋找一個可執行序列:
P2 -> P1 -> P3 -> P4(還有其他序列)
如果此時 P1 申請了 0 0 1,那麼就沒有可執行序列了,所以不可以滿足 P1 的申請
總結:銀行家算法首先要知道進程需要的最大資源量,然後當其申請資源時,用算法來檢測一遍如果把這個資源分配給了該進程,現在運行着的進程會不會出現死鎖,如果不會,就分配;否則不分配。所以如果使用死鎖避免,系統中永遠不會出現死鎖。
2.4 死鎖檢測和恢復
死鎖檢測與死鎖避免的思路不同,但是採用的算法相似。死鎖檢測就是每當進程申請資源時,都會滿足它,然後每隔一段時間進行一次檢查,看進程集合中是否存在一個使全部進程都能順利完成的可執行序列(檢測方式與上述圖中的方式一樣),如果有,就沒有死鎖;否則系統中就存在死鎖,需要進行死鎖恢復。
死鎖恢復:
- 利用搶佔恢復:把某個進程的資源臨時轉移到另一個進程上,就是把當前進程掛起
- 利用回滾恢復:設置檢查點,如果在一個檢查點發現了死鎖,就把系統中的工作恢復到上一個檢查點。
- 通過殺死進程恢復:殺死一個或若干個進程來打破環。