1. 程式人生 > >基本概念(死鎖,活鎖,餓死,優先順序反轉,護航現象)

基本概念(死鎖,活鎖,餓死,優先順序反轉,護航現象)

死鎖(deadlock

是指兩個或兩個以上的程序在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的程序稱為死鎖程序。

雖然程序在執行過程中,可能發生死鎖,但死鎖的發生也必須具備一定的條件,死鎖的發生必須具備以下四個必要條件。

1)互斥條件:指程序對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個程序佔用。如果此時還有其它程序請求資源,則請求者只能等待,直至佔有資源的程序用畢釋放。
2)請求和保持條件:指程序已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它程序佔有,此時請求程序阻塞,但又對自己已獲得的其它資源保持不放。


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

4)環路等待條件:指在發生死鎖時,必然存在一個程序——資源的環形鏈,即程序集合{P0P1P2···Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……Pn正在等待已被P0佔用的資源。

理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、程序排程等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配演算法,避免程序永久佔據系統資源。此外,也要防止程序在處於等待狀態的情況下佔用資源,在系統執行過程中,對程序發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,若分配後系統可能發生死鎖,則不予分配,否則予以分配。因此,對資源的分配要給予合理的規劃。

避免死鎖演算法1

有序資源分配法
這種演算法資源按某種規則系統中的所有資源統一編號(例如印表機為1、磁帶機為2、磁碟為3等等),申請時必須以上升的次序。系統要求申請程序:
1、對它所必須使用的而且屬於同一類的所有資源,必須一次申請完;
2、在申請不同類資源時,必須按各類裝置的編號依次申請。

例如:

程序PA,使用資源的順序是R1R2

程序PB,使用資源的順序是R2R1

若採用動態分配有可能形成環路條件,造成死鎖。
採用有序資源分配法:R1的編號為1R2的編號為2
PA:申請次序應是:R1R2
PB
:申請次序應是:R1R2
這樣就破壞了環路條件,避免了死鎖的發生。

避免死鎖演算法2


銀行演算法
避免死鎖演算法中最有代表性的演算法是DijkstraE.W1968年提出的銀行家演算法:
該演算法需要檢查申請者對資源的最大需求量,如果系統現存的各類資源可以滿足申請者的請求,就滿足申請者的請求。
這樣申請者就可很快完成其計算,然後釋放它佔用的資源,從而保證了系統中的所有程序都能完成,所以可避免死鎖的發生。

活鎖(livelock

指事物1可以使用資源,但它讓其他事物先使用資源;

事物2可以使用資源,但它也讓其他事物先使用資源,於是兩者一直謙讓,都無法使用資源。

避免活鎖的簡單方法是採用先來先服務的策略。當多個事務請求封鎖同一資料物件時,封鎖子系統按請求封鎖的先後次序對事務排隊,資料物件上的鎖一旦釋放就批准申請佇列中第一個事務獲得鎖。

飢餓(hungry

所謂飢餓,是指如果事務T1封鎖了資料R,事務T2又請求封鎖R,於是T2等待。T3也請求封鎖R,當T1釋放了R上的封鎖後,系統首先批准了T3的請求,T2仍然等待。然後T4又請求封鎖R,當T3釋放了R上的封鎖之後,系統又批准了T4的請求......T2可能永遠等待,這就是飢餓。

優先順序反轉(Priority inversion

優先順序反轉是指一個低優先順序的任務持有一個被高優先順序任務所需要的共享資源。高優先任務由於因資源缺乏而處於受阻狀態,一直等到低優先順序任務釋放資源為止。而低優先順序獲得的CPU時間少,如果此時有優先順序處於兩者之間的任務,並且不需要那個共享資源,則該中優先順序的任務反而超過這兩個任務而獲得CPU時間。如果高優先順序等待資源時不是阻塞等待,而是忙迴圈,則可能永遠無法獲得資源,因為此時低優先順序程序無法與高優先順序程序爭奪CPU時間,從而無法執行,進而無法釋放資源,造成的後果就是高優先順序任務無法獲得資源而繼續推進。

解決方案:1)設定優先順序上限,給臨界區一個高優先順序,進入臨界區的程序都將獲得這個高優先順序,如果其他試圖進入臨界區的程序的優先順序都低於這個高優先順序,那麼優先順序反轉就不會發生。

2)優先順序繼承,當一個高優先順序程序等待一個低優先順序程序持有的資源時,低優先順序程序將暫時獲得高優先順序程序的優先級別,在釋放共享資源後,低優先順序程序回到原來的優先級別。嵌入式系統VxWorks就是採用這種策略。

這裡還有一個八卦,1997年的美國的火星探測器(使用的就是vxworks)就遇到一個優先順序反轉問題引起的故障。簡單說下,火星探測器有一個資訊匯流排,有一個高優先順序的匯流排任務負責匯流排資料的存取,訪問匯流排都需要通過一個互斥鎖(共享資源出現了);還有一個低優先順序的,執行不是很頻繁的氣象蒐集任務,它需要對匯流排寫資料,也就同樣需要訪問互斥鎖;最後還有一箇中優先順序的通訊任務,它的執行時間比較長。平常這個系統執行毫無問題,但是有一天,在氣象任務獲得互斥鎖往匯流排寫資料的時候,一箇中斷髮生導致通訊任務被排程就緒,通訊任務搶佔了低優先順序的氣象任務,而無巧不成書的是,此時高優先順序的匯流排任務正在等待氣象任務寫完資料歸還互斥鎖,但是由於通訊任務搶佔了CPU並且執行時間比較長,導致氣象任務得不到CPU時間也無法釋放互斥鎖,本來是高優先順序的匯流排任務也無法執行,匯流排任務無法及時執行的後果被探路者認為是一個嚴重錯誤,最後就是整個系統被重啟。Vxworks允許優先順序繼承,然而遺憾的工程師們將這個選項關閉了。

3)第三種方法就是使用中斷禁止,通過禁止中斷來保護臨界區,採用此種策略的系統只有兩種優先順序:可搶佔優先順序和中斷禁止優先順序。前者為一般程序執行時的優先順序,後者為運行於臨界區的優先順序。火星探路者正是由於在臨界區中執行的氣象任務被中斷髮生的通訊任務所搶佔才導致故障,如果有臨界區的禁止中斷保護,此一問題也不會發生。

護航現象(Lock Convoys

Lock Convoys是在多執行緒併發環境下由於鎖的使用而引起的效能退化問題。

當多個相同優先順序的執行緒頻繁地爭搶同一個鎖時可能會引起lockconvoys問題,一般而言,lockconvoys並不會像deadlocklivelock那樣造成應用邏輯停止不前,相反地,遭受lock convoys的系統或應用程式仍然往前執行,但是,由於執行緒們頻繁地爭搶鎖而導致過多的執行緒環境切換,從而使得系統的執行效率大為降低,而且,若存在同等優先順序下不參與鎖爭搶的執行緒,則它們可以獲得相對較多的處理器資源,從而造成系統排程的不公平性。

本文將解釋lockconvoys問題的緣由。

假設一組執行緒在頻繁地獲取鎖(所謂頻繁,指在一個時間片的執行週期內多次獲取鎖),比如在Windows應用程式中常常用臨界區(criticalsection)來保護一個共享變數或者防止一段程式碼被重入,這是極有可能發生的。

假設執行緒A獲取到了鎖,這時發生了執行緒排程中斷,它的時間片用完了,於是,系統排程器交給下一個執行緒執行,不妨設執行緒B獲得了執行權。由於此鎖被執行緒A獲取,所以,當執行緒B執行到獲取鎖的操作時,雖然時間片未用完,但不得不放棄執行權。如此繼續,所有同等優先順序且要競爭此鎖的執行緒都被阻塞。排程器再次回到執行緒A,很快地執行緒A釋放了鎖。在作業系統中,釋放一個鎖,意味著核心中如果有執行緒正在等待該鎖,則它的狀態就可以變成執行態。比如,執行緒B的獲取操作成功。但此時,核心只是將執行緒B標記為鎖的所有者,而執行緒A繼續執行。很快地,執行緒A又要獲取鎖了,由於該鎖已經被標記給執行緒B了,所以執行緒A不得不放棄時間片,將控制權交給排程器。排程器終於可以撿起執行緒B,將處理器的執行權交給它。等到執行緒B釋放了鎖,下一個執行緒獲得鎖的所有權,並且等到執行緒B放棄執行權或者結束時間片之後就有機會被執行。此過程一直持續,經過一輪之後又會回到執行緒A,從而繼續下一輪的爭搶。在此期間,這些執行緒總是未執行滿時間片就不得不放棄執行權。下面的圖說明了三個執行緒在爭搶一個鎖時候的執行情況。

假設一個執行緒在一個滿時間片的執行過程中要多次獲取/釋放鎖,它一旦釋放了鎖,則意味著,只要存在鎖競爭,它在分配給它的當前時間片內已經無法再重新獲得鎖了。所以,它只能執行到它的下一次獲取操作為止。譬如,參與競爭的執行緒平均執行1/3時間片就要獲取鎖,那麼,執行緒的實際執行時間變成了1/3時間片。系統的排程粒度變成原來的1/3時間間隔。這引起了3倍數量的執行緒切換。從上圖的右半部分可以看出,每個執行緒在一輪的迴圈中,只有1/3時間片的機會。這導致了3倍的執行緒切換。

除了引起排程粒度變小以外,lockconvoys的另一個問題是造成排程器的時間分配不公平。假設另有一個執行緒X也是在同等的優先順序上執行,但沒有參與鎖競爭。於是,在每一輪的鎖競爭過程中,執行緒X都有機會被分配一次完整的時間片,於是,這些競爭的執行緒在一輪中獲得1/3時間片,而非競爭的執行緒可以獲得完整的時間片。當然,你可以說這種不公平是由於它們搶鎖而引起的,但從時間分配比例而言,參與競爭與不參與競爭的執行緒是不公平的。下圖說明了執行緒XABC之間的執行時間差異。

由以上描述可以看出,Lockconvoys的存在條件是,參與競爭的執行緒頻繁地獲取鎖,鎖被一個執行緒釋放以後其所有權便落到了另一個執行緒的手裡。在作業系統中,相同優先順序的執行緒按照FIFO的順序被排程和執行,競爭同一個鎖的執行緒也按照FIFO的順序被依次成功地獲取到鎖。這些條件在現代作業系統中都能被滿足,包括Windows

Lock convoys雖然不是致命的問題,但也可能在實際系統中發生。Sue Loh在她的部落格文章中展示了在Windows CE中發生的lock convoy問題。她也討論了一種合理的緩解lockconvoy的方案,要求在每個執行緒獲取鎖的時候先嚐試(try),如果嘗試多次仍不成功,再阻塞。

References: