標籤:死結
1、什麼是死結
指兩個或兩個以上的進程(線程)在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死結狀態或系統產生了死結,這些永遠在互相等待的進程(線程)稱為死結進程(線程)。 由於資源佔用是互斥的,當某個進程提出申請資源後,使得有關進程(線程)在無外力協助下,永遠分配不到必需的資源而無法繼續運行,這就產生了一種特殊現象死結。
第一種情況:
如果同一個線程先後兩次調用lock,在第二次調用時,由於鎖已經被佔用,該線程會掛起等待別的線程釋放鎖,然而鎖正是被自己佔用著的,該線程又被掛起而沒有機會釋放鎖,因此就永遠處於掛起等待狀態了,這也叫做死結(Deadlock)。
第二種情況:
一種交叉持鎖死結的情形,此時執行程式中兩個或多個線程發生永久堵塞(等待),每個線程都在等待被其它線程佔用並堵塞了的資源。例如,如果線程 1 鎖住了記錄 A 並等待記錄 B,而線程 2 鎖住了記錄 B 並等待記錄 A,這樣兩個線程就發生了死結現象。
2、死結產生的原因
(1) 因為系統資源不足。
(2) 進程運行推進的順序不合適。
(3) 資源分派不當等。
如果系統資源充足,進程的資源請求都能夠得到滿足,死結出現的可能性就很低,否則就會因爭奪有限的資源而陷入死結。其次,進程運行推進順序與速度不同,也可能產生死結。
3、死結產生的必要條件
(1) 互斥條件:一個資源每次只能被一個進程使用。
(2) 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 迴圈等待條件:若干進程之間形成一種頭尾相接的迴圈等待資源關係。
以上四個條件只要有一條不滿足,就不會出現死結。
4、死結預防
(1)有序資源分派法
這種演算法資源按某種規則系統中的所有資源統一編號,申請時必須以上升的次序。系統要求申請進程:
1)對它所必須使用的而且屬於同一類的所有資源,必須一次申請完;
2)在申請不同類資源時,必須按各類裝置的編號依次申請。例如:進程PA,使用資源的順序是R1,R2; 進程PB,使用資源的順序是R2,R1;若採用動態分配有可能形成環路條件,造成死結。
採用有序資源分派法:R1的編號為1,R2的編號為2;
PA:申請次序應是:R1,R2
PB:申請次序應是:R1,R2
這樣就破壞了環路條件,避免了死結的發生。
(2)銀行家演算法
避免死結演算法中最有代表性的演算法是Dijkstra E.W 於1968年提出的銀行家演算法:
銀行家演算法是避免死結的一種重要方法,防止死結的機構只能確保上述四個條件之一不出現,則系統就不會發生死結。
在作業系統中研究資源分派策略時,系統中有限的資源要供多個進程使用,必須保證得到的資源的進程能在有限的時間內歸還資源,以供其他進程使用資源。如果資源分派不得到就會發生進程迴圈等待資源,則進程都無法繼續執行下去的死結現象。
把一個進程需要和已佔有資源的情況記錄在進程式控制制中,假定進程式控制制塊PCB其中“狀態”有就緒態、等待態和完成態。當進程在處於等待態時,表示系統不能滿足該進程當前的資源申請。“資源需求總量”表示進程在整個執行過程中總共要申請的資源量。顯然,每個進程的資源需求總量不能超過系統擁有的資源總數, 銀行演算法進行資源分派可以避免死結。
5、避免死結的方法
(1) 加鎖順序
當多個線程需要相同的一些鎖,但是按照不同的順序加鎖,死結就很容易發生。 如果能確保所有的線程都是按照相同的順序獲得鎖,那麼死結就不會發生。 按照順序加鎖是一種有效死結預防機制。但是,這種方式需要你事Crowdsourced Security Testing道所有可能會用到的鎖,但總有些時候是無法預知的。
(2) 加鎖時限
另外一個可以避免死結的方法是在嘗試擷取鎖的時候加一個逾時時間,這也就意味著在嘗試擷取鎖的過程中若超過了這個時限該線程則放棄對該鎖請求。若一個線程沒有在給定的時限 內成功獲得所有需要的鎖,則會進行回退並釋放所有已經獲得的鎖,然後等待一段隨機的時 間再重試。這段隨機的等待時間讓其它線程有機會嘗試擷取相同的這些鎖,並且讓該應用在沒有獲得鎖的時候可以繼續運行(加鎖逾時後可以先繼續運行幹點其它事情,再回頭來重複之前加鎖的邏輯)。
(3) 死結檢測
死結檢測是一個更好的死結預防機制,它主要是針對那些不可能實現按序加鎖並且鎖逾時也不可行的情境。
每當一個線程獲得了鎖,會線上程和鎖相關的資料結構中(map、graph 等等)將其記下。 除此之外,每當有線程請求鎖,也需要記錄在這個資料結構中。 當一個線程請求鎖失敗時,這個線程可以遍曆鎖的關係圖看看是否有死結發生。
當然,死結一般要比兩個線程互相持有對方的鎖這種情況要複雜的多。線程A等待線程B,線程B等待線程 C,線程C等待線程D,線程D又在等待線程A。線程A為了檢測死結,它需要遞進地檢測所有被B請求的鎖。從線程B所請求的鎖開始,線程A找到了線程C,然後又找到了線程D,發現線程D請求的鎖被線程A自己持有著。這是它就知道發生了死結。
當檢測出死結時,最好的的做法是給這些線程設定優先權,讓一個(或幾個)線程回退,剩下的線程就像沒發生死結一樣繼續保持著它們需要的鎖。如果賦予這些線程的優先順序是固定不變的,同一批線程總是會擁有更高的優先順序。為避免這個問題,可以在死結發生的時候設定隨機的優先順序。
本文出自 “LOVEMERIGHT” 部落格,請務必保留此出處http://lovemeright.blog.51cto.com/10808587/1826593
淺談死結