死鎖:死鎖指的是系統中并發執行的多個線程(進程)由于無法獲所需的資源而永久阻塞的狀態。
死鎖產生的必要條件:
A.排它性互斥:指的是資源在任意時刻只能由一個任務(線程或進程)使用。如果此時還有其它任務請求該資源,則請求者只能等待,直至占有資源的任務釋放資源。
B.不可搶占:指的是當一個任務擁有某種資源時,除非它主動釋放它,否則無法讓該任務失去該資源的擁有權。
C.持有和等待:指的是任務已經擁有了至少一種資源,然后又等待其它資源可用。
D.循環等待:指在發生死鎖時,必然存在一個任務——資源的環形鏈,即任務集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。
產生死鎖時這4個必要條件都必須被滿足,因而處理死鎖就是要避免、預防這4個條件同時成立,或者在4個條件同時成立時破壞其中的任意一個條件。處理死鎖的方法包括:
該方法是為資源申請設置某些限制條件,去破壞產生死鎖的四個必要條件中的一個或者幾個,來預防發生死鎖。預防死鎖是一種較易實現的方法,已被廣泛使用。但是由于所施加的限制條件往往太嚴格,可能會導致系統資源利用率和系統吞吐量降低。
使用的限制條件一般有:
A.消除持有和等待這個條件:任務要一次申請完它所有需要的資源,只有當所有資源都可以獲得時它才能繼續運行。由于要求任務一次申請完其所有的所有資源,因而就不存在持有和等待這種情況。但是其不足在于:在實際的系統中很難預測一個任務需要那些資源,而且即便可以預測出來任務所需的資源,任務在運行時也不一定就要用到這些資源,因為運行中真正需要的資源是由代碼路徑決定的,這就可能造成占有了不使用的資源從而導致出現浪費;更嚴重的問題在于,使用該防范隱含著一個要求,即任務所需要的資源必須同時被釋放。這就意味著所有的資源都只能在任務已經不需要任何資源時才能被釋放,這會造成極大的資源浪費。
B.消除不可搶占這個條件:如果任務申請新的資源的請求不能被滿足,它就應該釋放它已經持有的資源。隨后任務再次嘗試申請資源的時候應該申請以前已經持有的資源和新需要的資源。與第一種條件相比,這種條件不需要任務一次申請其所需的所有資源,而是根據需要申請。但是該方法也存在嚴重的不足,因而它在申請一種資源失敗后,就會釋放所有已經持有的資源,當重新嘗試申請資源時就要申請這個時候所需的所有資源,這就需要追蹤所需的資源,而且在再次嘗試時,可能以前已經被持有過的資源也變的不可用了,這無疑加大了編程的復雜度。
C.消除循環等待這個條件: 該方法要求給資源進行統一編號,如果任務已經持有了編號為i的資源,則它只能申請編號大于i的資源。這就消除了循環等待這個條件。
該方法同樣是屬于事先預防的策略,但它并不須事先采取各種限制措施去破壞產生死鎖的的四個必要條件,而是在資源的動態分配過程中,用某種方法去防止系統進入不安全狀態,從而避免發生死鎖。避免死鎖算法中最有代表性的算法是Dijkstra E.W 于1968年提出的銀行家算法:銀行家算法是一種最有代表性的避免死鎖的算法。在避免死鎖方法中允許任務動態地申請資源,但系統在進行資源分配之前,應先計算此次分配資源的安全性,若分配不會導致系統進入不安全狀態,則分配,否則等待。安全序列是指一個任務序列{P1,…,Pn}是安全的,即對于每一個任務Pi(1≤i≤n),它之后的任務所需要的資源量不超過系統當前剩余資源量與所有進程Pj (j < i )當前占有資源量之和。安全狀態和不安全狀態:
為了使用該策略,每個任務都需要預估它所需要的最大資源量,然后系統使用該信息建立一個資源需求表以供使用。但是通常這種預估都是比較困難的。而且由于預估的是最大資源量,而實際運行中一個任務并不一定會真正用到完它所預估的最大資源量,因而使用這種預估進行死鎖避免時有可能導致不必要的阻塞。
死鎖檢測并不須事先采取任何限制性措施,它只用于在運行過程中發生死鎖。并精確地確定與死鎖有關的任務和資源,然后就可以采取適當措施,從系統中將已發生的死鎖清除掉。
所謂單實例資源即該資源只有1個,因此也只能被一個任務所申請使用。
所謂多實例資源即該資源有多個,因此在同一時間可能被多個任務所使用
它一般與檢測死鎖一起使用。常用的實施方法是撤銷或掛起一些任務,以便回收一些資源,再將這些資源分配給已處于阻塞狀態的任務,使之轉為就緒狀態,以繼續運行。死鎖的檢測和解除措施,有可能使系統獲得較好的資源利用率和吞吐量,但在實現上難度也最大。
這些策略一般都是由系統實現和支持的,在應用程序的編寫中也有一些原則可供參考:
A.不要在可能會對性能造成不良影響的長時間操作(如 I/O)中持有鎖。
B.不要在調用模塊外且可能重進入模塊的函數時持有鎖。
C.一般情況下,優先使用粗粒度鎖,如果確定粗粒度鎖對性能造成了很大影響,再使用細粒度鎖。
D.使用多個鎖時,盡量讓所有任務都按照相同的順序來上鎖以避免死鎖。
優先級逆轉:優先級逆轉指的是在可搶占系統中,高優先級任務由于等待低優先級任務所持有的資源而阻塞,同時低優先級優先運行的狀態。它的基本表現有兩種情形:
A.低優先級T1任務持有資源R運行;高優先級任務T2啟動開始運行,高優先級任務需要使用資源R,但是無法獲得該資源,因而阻塞;低優先級任務T1繼續運行,看上去好像高優先級任務被低優先級任務搶占了
B.低優先級T1任務持有資源R運行;高優先級任務T2啟動開始運行,高優先級任務需要使用資源R,但是無法獲得該資源,因而阻塞;低優先級任務T1被調度運行;此時一個優先級小于T2但是大于T1的任務T3啟動了,它就會搶占任務T1;最終看起來好像任務T3搶 占了高優先級任務T2,如果說情形1由于競爭資源還比較容易看出來的話,情形2則更具有迷惑性,T2和T3之間不存在競爭關系,T3竟然在T1之前運行了。
大部分情況下優先級逆轉并不導致問題,因為高優先級任務只是延遲執行了,但是有時候這也會是個問題。
由于優先級逆轉和資源的共享使用有關,因而可以通過對資源添加訪問控制協議來解決這個問題,可以通過如下三種資源訪問控制協議來解決優先級逆轉問題:
A.優先級繼承協議
B.天花板優先級協議
C.優先級天花板協議
該協議的訪問控制規則:如果一個任務T1由于無法獲取資源R而阻塞,并且其優先級高于資源R的持有者T2的優先級,就提升其持有者T2的優先級到任務T1的優先級。具體的規則:
在天花板優先級中,所有任務所需要的所有資源都是已知的,所有任務的優先級也是已知的。每種資源都有一個天花板優先級,它等于所有需要使用該資源的任務的最高優先級。比如系統中有任務T1(優先級4)、T2(優先級6)、T3(優先級8)、T4(優先級10),資源R1、R2、R3、R4,其中任務T1需要使用資源R1、R3,任務T2需要使用資源R2,任務T3需要使用資源R2、R4,任務T4需要使用資源R1、R3、R4.則資源R1、R2、R3、R4的天花板優先級分別為:10,8,10,10。使用該協議時的規則為:
類似于天花板優先級協議,在優先級天花板協議中所有任務所需要的所有資源都是已知的,所有任務的優先級也是已知的。每種資源都有一個天花板優先級,它等于所有需要使用該資源的任務的最高優先級。比如系統中有任務T1(優先級4)、T2(優先級6)、T3(優先級8)、T4(優先級10),資源R1、R2、R3、R4,其中任務T1需要使用資源R1、R3,任務T2需要使用資源R2,任務T3需要使用資源R2、R4,任務T4需要使用資源R1、R3、R4.則資源R1、R2、R3、R4的天花板優先級分別為:10,8,10,10。二者不同之處在于規則,在優先級天花板協議中有一個當前優先級天花板,當前優先級天花板等于當前正被使用的所有資源的最高天花板優先級,基于當前優先級天花板,該協議的規則為:
該協議結合了優先級繼承協議和天花板優先級協議,用當前正在被使用的資源的優先級天花板計算出了一個當前天花板優先級,但是它又不同于運行任務的優先級;任務的運行優先級只有在任務阻塞了一個高優先級任務時才會改變,而且這個改變不是簡單的設置為當前優先級變化板,而是繼承它所阻塞的高優先級任務的優先級
經常見到的一個需求是使得應用程序只有一個運行實例在運行。這可以通過記錄鎖來實現,實現方法是:
A.在啟動應用后創建一個特殊文件,該文件的位置和名字是特定唯一的
B.嘗試在該文件上上一個記錄鎖寫鎖,并鎖住整個文件
C.如果上鎖失敗,說明有一個應用實例在運行,退出
D.繼續執行
之所以記錄鎖可以實現該目的是因為:根據記錄鎖的特性,無論記錄鎖的持有者進程以何種方式結束,系統都會自動釋放它所持有的所有記錄鎖--如果進程沒有自己釋放它的話。因而只要無法鎖定就肯定表明有一個正在運行的實例正在持有這把鎖。
由于命名信號量也具有類似的特性(系統會在進程終止時自動關閉其打開的所有命名信號量),因而命名信號量也可以用于該目的。
新聞熱點
疑難解答