1. 程式人生 > >死鎖的原理及避免死鎖的方法

死鎖的原理及避免死鎖的方法

死鎖

所謂死鎖,指的是兩個或兩個以上的程序在執行過程中,由於競爭資源或者由於彼此通訊而造成的一種阻塞的現象,如果無外力作用,那麼它們都將無法推進下去。此時,稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的程序稱為死鎖程序。

舉例說明死鎖:如果一個執行緒需要並行處理多個任務,那麼就可以建立多個執行緒,但是執行緒多了,往往會產生衝突,當一個執行緒鎖定了一個資源A,而又想去鎖定資源B,而在另一個執行緒中,鎖定了資源B,而又想去鎖定資源A以完成自身的操作,兩個執行緒都想得到對方的資源,而不願意釋放自己的資源,造成兩個執行緒都在等待,而無法執行,此時就是死鎖。

死鎖的規範定義:集合中的每一個程序都在等待只能由本集合中的其他程序才能引發的事件,那麼該組程序是死鎖的。

注意 死鎖與正常阻塞不一樣
正常阻塞:事務請求被其他事務鎖定的資源的鎖時,發出請求的事務一直等到該鎖被釋放。預設情況下,除非設定了LOCK_TIMEOUT,否則SQL Server事務不會超時。因為發出請求的事務未執行任何操作來阻塞擁有鎖的事務,所以該事務是被阻塞,而不是陷入了死鎖。最後,擁有鎖的事務將完成並釋放鎖,然後發出請求地事務將獲取鎖並繼續執行。

產生條件

-互斥(資源獨佔): 一個資源每次只能被一個程序使用;
- 請求與保持(部分分配,佔有申請):一個程序在申請新的資源的同時保持對原有資源的佔有(只有這樣才是動態申請,動態分配);
- 不可剝奪(不可強佔):

資源申請者不能強行地從資源佔有者手中奪取資源,資源只能由佔有者自願釋放;
- 迴圈等待:若干程序之間形成一種頭尾相連的迴圈等待資源關。

迴圈等待的例子:例如,存在一個程序等待佇列{P1, P2, ……, Pn},其中P1等待P2佔有的資源,P2等待P3佔有的資源,……, Pn等待P1佔有的資源,形成一個程序等待環路。

以上四個條件是死鎖產生的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。

產生原因

系統中的資源可以分為兩類:可剝奪資源和不可剝奪資源。
可剝奪資源:是指某程序在獲得這類資源後,該資源可以再被其他程序或系統剝奪。例如,優先權高的程序可以剝奪優先權低的程序的處理機;可把一個程序從一個儲存區移到另一個儲存區;在記憶體緊張時,甚至可將一個程序從記憶體調到外存上,即剝奪該程序在記憶體的空間。可見,CPU和主存均屬於可剝奪性資源。對於這類資源是不會引起死鎖的。
不可剝奪資源

:當系統把某資源分配給某程序後,就不能將它強行收回,只能在程序用完後自行釋放。例如,當一個程序已開始燒錄光碟時,如果突然將燒錄機分配給另一個程序,其結果必然會損壞正在刻錄的光碟,因此只能等刻好光碟後由程序自己釋放燒錄機。另外磁帶機、印表機也是不可剝奪資源。


  • 系統資源不足時,競爭不可剝奪資源引起程序死鎖

在系統中所配置的不可剝奪資源,由於它們的數量不能滿足諸程序執行的需要,會使程序在執行過程中,因爭奪這些資源而陷於僵局。
例如,當系統中供多個程序共享的資源如印表機、公用佇列等,其數目不足以滿足諸程序的需要時,會引起諸程序對資源的競爭而產生死鎖。
例如,系統中只有一臺印表機R1和一臺磁帶機R2,可供程序P1和P2共享。假定PI已佔用了印表機R1,P2已佔用了磁帶機R2,若P2繼續要求印表機R1,P2將阻塞;P1若又要求磁帶機,P1也將阻塞。於是,在P1和P2之間就形成了僵局,兩個程序都在等待對方釋放自己所需要的資源,但是它們又都因不能繼續獲得自己所需要的資源而不能繼續推進,從而也不能釋放自己所佔有的資源,以致進入死鎖狀態。

  • 競爭臨時資源引起死鎖

    永久資源:上面所說的印表機資源屬於可順序重複使用型資源,稱為永久資源。
    臨時資源:還有一種所謂的臨時資源,這是指由一個程序產生,被另一個程序使用,短時間後便無用的資源,故也稱為消耗性資源,如硬體中斷、訊號、訊息、緩衝區內的訊息等,它也可能引起死鎖。
    如果訊息通訊按如下順序進行:
    P1: ···Relese(S1);Request(S3); ···
    P2: ···Relese(S2);Request(S1); ···
    P3: ···Relese(S3);Request(S2); ···
    並不可能發生死鎖。
    但若改成下述的執行順序:
    P1: ···Request(S3);Relese(S1);···
    P2: ···Request(S1);Relese(S2); ···
    P3: ···Request(S2);Relese(S3); ···
    則可能發生死鎖。

  • 程序推進順序不當引起死鎖

    由於程序在執行中具有非同步性特徵,這可能使P1和P2兩個程序按下述兩種順序向前推進。
    1) 程序推進順序合法
    當程序P1和P2併發執行時,如果按照下述順序推進:
    P1:Request(R1); P1:Request(R2); P1: Relese(R1);
    P1:Relese(R2); P2:Request(R2); P2:Request(R1);
    P2:Relese(R2);P2:Relese(R1);
    這兩個程序便可順利完成,這種不會引起程序死鎖的推進順序是合法的。
    2) 程序推進順序非法
    若P1保持了資源R1,P2保持了資源R2,系統處於不安全狀態,因為這兩個程序再向前推進,便可能發生死鎖。
    例如,當P1執行到P1:Request(R2)時,將因R2已被P2佔用而阻塞;當P2執行到P2:Request(R1)時,也將因R1已被P1佔用而阻塞,於是發生程序死鎖。

  • 預防死鎖

    預防死鎖的方法是通過設定某些限制條件,去破壞產生死鎖的四個必要條件中的一個或者幾個,以避免發生死鎖。
    由於互斥條件是非共享裝置所必須的,不僅不能改變,還應該加以保證,因此,主要是破壞產生死鎖的後三個條件。

    • 破壞請求與保持條件:對一個程序在請求資源時,它不能持有不可剝奪資源。
    • 破壞不可剝奪條件:對一個已經保持了某些不可剝奪資源的程序,提出新的資源請求而不能得到滿足時,它必須釋放已經保持的所有資源,待以後需要時再重新申請。
    • 破壞迴圈等待條件:對系統所有資源型別進行線性排列,並賦予不同序號。規定每個程序必須按序號遞增的順序請求資源。

    避免死鎖的方法

    • 一次封鎖法:每個程序(事務)將所有要使用的資料全部加鎖,否則,就不能繼續執行;
    • 順序封鎖法:預先對資料物件規定一個封鎖順序,所有程序(事務)都按這個順序加鎖;
    • 銀行家演算法:保證程序處於安全程序序列。

    有助於最大限度地降低死鎖的方法

    • 按同一順序訪問物件;
    • 避免事務中的使用者互動;
    • 保持事務簡短並在一個批處理中;
    • 使用低隔離級別。