死鎖(deadlock)
是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
雖然進程在運行過程中,可能發生死鎖,但死鎖的發生也必須具備一定的條件,死鎖的發生必須具備以下四個必要條件。
1)互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程占用。如果此時還有其它進程請求資源,則請求者只能等待,直至占有資源的進程用畢釋放。
2)請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。
3)不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。
4)環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久占據系統資源。此外,也要防止進程在處於等待狀態的情況下占用資源,在系統運行過程中,對進程發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,若分配后系統可能發生死鎖,則不予分配,否則予以分配。因此,對資源的分配要給予合理的規划。
避免死鎖算法1:
有序資源分配法
這種算法資源按某種規則系統中的所有資源統一編號(例如打印機為1、磁帶機為2、磁盤為3等等),申請時必須以上升的次序。系統要求申請進程:
1、對它所必須使用的而且屬於同一類的所有資源,必須一次申請完;
2、在申請不同類資源時,必須按各類設備的編號依次申請。
例如:
進程PA,使用資源的順序是R1,R2;
進程PB,使用資源的順序是R2,R1;
若采用動態分配有可能形成環路條件,造成死鎖。
采用有序資源分配法:R1的編號為1,R2的編號為2;
PA:申請次序應是:R1,R2
PB:申請次序應是:R1,R2
這樣就破壞了環路條件,避免了死鎖的發生。
避免死鎖算法2:
銀行算法
避免死鎖算法中最有代表性的算法是DijkstraE.W於1968年提出的銀行家算法:
該算法需要檢查申請者對資源的最大需求量,如果系統現存的各類資源可以滿足申請者的請求,就滿足申請者的請求。
這樣申請者就可很快完成其計算,然后釋放它占用的資源,從而保證了系統中的所有進程都能完成,所以可避免死鎖的發生。
活鎖(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並不會像deadlock或livelock那樣造成應用邏輯停止不前,相反地,遭受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時間片,而非競爭的線程可以獲得完整的時間片。當然,你可以說這種不公平是由於它們搶鎖而引起的,但從時間分配比例而言,參與競爭與不參與競爭的線程是不公平的。下圖說明了線程X和A、B、C之間的執行時間差異。

由以上描述可以看出,Lockconvoys的存在條件是,參與競爭的線程頻繁地獲取鎖,鎖被一個線程釋放以后其所有權便落到了另一個線程的手里。在操作系統中,相同優先級的線程按照FIFO的順序被調度和執行,競爭同一個鎖的線程也按照FIFO的順序被依次成功地獲取到鎖。這些條件在現代操作系統中都能被滿足,包括Windows。
Lock convoys雖然不是致命的問題,但也可能在實際系統中發生。Sue Loh在她的博客文章中展示了在Windows CE中發生的lock convoy問題。她也討論了一種合理的緩解lockconvoy的方案,要求在每個線程獲取鎖的時候先嘗試(try),如果嘗試多次仍不成功,再阻塞。
References:
[1] Sue Loh, Lock Convoys and How toRecognize Them,http://blogs.msdn.com/b/sloh/archive/2005/05/27/lock-convoys-and-how-to-recognize-them.aspx,2005.
[2] Lock Convoys, http://en.wikipedia.org/wiki/Lock_convoy
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
