所謂的死鎖,是指兩個或者兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象。若無外力做用,它們都將沒法推動下去。咱們來看一個例子更好的理解一下:python
咱們先看看這樣一個生活中的例子:在一條河上有一座橋,橋面較窄,只能容納一輛汽車經過,沒法讓兩輛汽車並行。若是有兩輛汽車A和B分別由橋的兩端駛上該橋,則對於A車來講,它走過橋面左面的一段路(即佔有了橋的一部分資源),要想過橋還須等待B車讓出右邊的橋面,此時A車不能前進;對於B車來講,它走過橋面右邊的一段路(即佔有了橋的一部分資源),要想過橋還須等待A車讓出左邊的橋面,此時B車也不能前進。兩邊的車都不倒車,結果形成互相等待對方讓出橋面,可是誰也不讓路,就會無休止地等下去。這種現象就是死鎖。算法
若是把汽車比作進程,橋面做爲資源,那麼上述問題就描述爲:進程A佔有資源R1,等待進程B佔有的資源Rr;進程B佔有資源Rr,等待進程A佔有的資源R1。並且資源R1和Rr只容許一個進程佔用,即:不容許兩個進程同時佔用。結果,兩個進程都不能繼續執行,若不採起其它措施,這種循環等待情況會無限期持續下去,就發生了進程死鎖。 安全
1. 由於系統資源不足併發
2. 進程運行推動的順序不合適性能
3. 資源分配不當spa
1. 互斥條件:所謂互斥就是進程在某一時間內獨佔資源操作系統
2. 請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。線程
3. 不剝奪條件:進程已得到資源,在未使用完以前,不能強行剝奪。code
4. 循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。進程
這個介紹的是死鎖發生的四個必要條件,只要破壞這四個必要條件中的任意一個條件,死鎖就不會發生。通常來講解決死鎖的方法分爲:預防,避免,檢測與恢復。
死鎖的預防是保證系統不進入死鎖狀態的一種策略。它的基本思想是要求進程申請資源時遵循某種協議,從而打破產生死鎖的四個必要條件中的一個或幾個,保證系統不會進入死鎖狀態。
這種作法的缺點是顯而易見的: (1)在許多狀況下,一個進程在執行以前不可能知道它所須要的所有資源。 這是因爲進程在執行時是動態的,不可預測的; (2)資源利用率低。不管所分資源什麼時候用到,一個進程只有在佔有所需的 所有資源後才能執行。即便有些資源最後才被該進程用到一次,但該進程在 生存期間卻一直佔有它們,形成長期佔着不用的情況。這顯然是一種極大的資源浪費; (3)下降了進程的併發性。由於資源有限,又加上存在浪費,能分配到所需 所有資源的進程個數就必然少了。
可是也存在如下缺點: (1)限制了進程對資源的請求,同時給系統中全部資源合理編號也是件困難事,並增長了系統開銷; (2)爲了遵循按編號申請的次序,暫不使用的資源也須要提早申請,從而增長了進程對資源的佔用時間。
上面咱們講到的死鎖預防是排除死鎖的靜態策略,它使產生死鎖的四個必要條件不能同時具有,從而對進程申請資源的活動加以限制,以保證死鎖不會發生。下面咱們介紹排除死鎖的動態策略--死鎖的避免,它不限制進程有關申請資源的命令,而是對進程所發出的每個申請資源命令加以動態地檢查,並根據檢查結果決定是否進行資源分配。就是說,在資源分配過程當中若預測有發生死鎖的可能性,則加以免。這種方法的關鍵是肯定資源分配的安全性。
咱們首先引入安全序列的定義:所謂系統是安全的,是指系統中的全部進程可以按照某一種次序分配資源,而且依次地運行完畢,這種進程序列{P1,P2,...,Pn}就是安全序列。若是存在這樣一個安全序列,則系統是安全的;若是系統不存在這樣一個安全序列,則系統是不安全的。
安全序列{P1,P2,...,Pn}是這樣組成的:若對於每個進程Pi,它須要的附加資源能夠被系統中當前可用資源加上全部進程Pj當前佔有資源之和所知足,則{P1,P2,...,Pn}爲一個安全序列,這時系統處於安全狀態,不會進入死鎖狀態。
雖然存在安全序列時必定不會有死鎖發生,可是系統進入不安全狀態(四個死鎖的必要條件同時發生)也未必會產生死鎖。固然,產生死鎖後,系統必定處於不安全狀態。
這是一個著名的避免死鎖的算法,是由Dijstra首先提出來並加以解決的。
一個銀行家如何將必定數目的資金安全地借給若干個客戶,使這些客戶既能借到錢完成要乾的事,同時銀行家又能收回所有資金而不至於破產,這就是銀行家問題。這個問題同操做系統中資源分配問題十分類似:銀行家就像一個操做系統,客戶就像運行的進程,銀行家的資金就是系統的資源。
例如:有三個客戶C1,C2,C3,向銀行家借款,該銀行家的資金總額爲10個資金單位,其中C1客戶要借9各資金單位,C2客戶要借3個資金單位,C3客戶要借8個資金單位,總計20個資金單位。某一時刻的狀態如圖所示。
|
|
|
|
(a) |
(b) |
(c) |
(d) |
銀行家算法示意
對於a圖的狀態,按照安全序列的要求,咱們選的第一個客戶應知足該客戶所需的貸款小於等於銀行家當前所剩餘的錢款,能夠看出只有C2客戶能被知足:C2客戶需1個資金單位,小銀行家手中的2個資金單位,因而銀行家把1個資金單位借給C2客戶,使之完成工做並歸還所借的3個資金單位的錢,進入b圖。同理,銀行家把4個資金單位借給C3客戶,使其完成工做,在c圖中,只剩一個客戶C1,它需7個資金單位,這時銀行家有8個資金單位,因此C1也能順利借到錢並完成工做。最後(見圖d)銀行家收回所有10個資金單位,保證不賠本。那麼客戶序列{C1,C2,C3}就是個安全序列,按照這個序列貸款,銀行家纔是安全的。不然的話,若在圖b狀態時,銀行家把手中的4個資金單位借給了C1,則出現不安全狀態:這時C1,C3均不能完成工做,而銀行家手中又沒有錢了,系統陷入僵持局面,銀行家也不能收回投資。
綜上所述,銀行家算法是從當前狀態出發,逐個按安全序列檢查各客戶誰能完成其工做,而後假定其完成工做且歸還所有貸款,再進而檢查下一個能完成工做的客戶,......。若是全部客戶都能完成工做,則找到一個安全序列,銀行家纔是安全的。
從上面分析看出,銀行家算法容許死鎖必要條件中的互斥條件,佔有且申請條件,不可搶佔條件的存在,這樣,它與預防死鎖的幾種方法相比較,限制條件少了,資源利用程度提升了。
這是該算法的優勢。其缺點是:
〈1〉這個算法要求客戶數保持固定不變,這在多道程序系統中是難以作到的。
〈2〉這個算法保證全部客戶在有限的時間內獲得知足,但實時客戶要求快速響應,因此要考慮這個因素。
〈3〉因爲要尋找一個安全序列,實際上增長了系統的開銷。
通常來講,因爲操做系統有併發,共享以及隨機性等特色,經過預防和避免的手段達到排除死鎖的目的是很困難的。這須要較大的系統開銷,並且不能充分利用資源。爲此,一種簡便的方法是系統爲進程分配資源時,不採起任何限制性措施,可是提供了檢測和解脫死鎖的手段:能發現死鎖並從死鎖狀態中恢復出來。所以,在實際的操做系統中每每採用死鎖的檢測與恢復方法來排除死鎖。
死鎖檢測與恢復是指系統設有專門的機構,當死鎖發生時,該機構可以檢測到死鎖發生的位置和緣由,並能經過外力破壞死鎖發生的必要條件,從而使得併發進程從死鎖狀態中恢復出來。
有一個專用的死鎖檢測算法
一旦在死鎖檢測時發現了死鎖,就要消除死鎖,使系統從死鎖狀態中恢復過來。
(1)最簡單,最經常使用的方法就是進行系統的從新啓動,不過這種方法代價很大,它意味着在這以前全部的進程已經完成的計算工做都將付之東流,包括參與死鎖的那些進程,以及未參與死鎖的進程。
(2)撤消進程,剝奪資源。終止參與死鎖的進程,收回它們佔有的資源,從而解除死鎖。這時又分兩種狀況:一次性撤消參與死鎖的所有進程,剝奪所有資源;或者逐步撤消參與死鎖的進程,逐步收回死鎖進程佔有的資源。通常來講,選擇逐步撤消的進程時要按照必定的原則進行,目的是撤消那些代價最小的進程,好比按進程的優先級肯定進程的代價;考慮進程運行時的代價和與此進程相關的外部做業的代價等因素。
此外,還有進程回退策略,即讓參與死鎖的進程回退到沒有發生死鎖前某一點處,並由此點處繼續執行,以求再次執行時再也不發生死鎖。雖然這是個較理想的辦法,可是操做起來系統開銷極大,要有堆棧這樣的機構記錄進程的每一步變化,以便從此的回退,有時這是沒法作到的。