作業系統知識回顧(4)-死鎖

TimberLiu發表於2019-01-10

在計算機系統中,死鎖很容易發現,但死鎖也不難處理。這篇文章總結了死鎖的基本概念、必要條件以及四種處理死鎖的方法。

死鎖概念

在兩個或多個併發程式中,如果一個程式集合中的每個程式都在等待只能由該程式集合中的其他程式才能引發的事件,那麼該程式集合就產生了死鎖。

死鎖產生的根本原因是多個程式競爭資源時,程式的推進順序出現不當。

出現死鎖的四個必要條件:

  • 互斥。在任何時刻一個資源只能被一個程式使用。
  • 擁有和請求。已經得到某個資源的程式可以再請求新的資源;
  • 不可搶佔。已經分配給程式的資源不能被搶佔,而只能被顯式釋放;
  • 迴圈等待。系統中有兩個或多個的程式組成一條迴圈,該迴圈中的每個程式都等待著另一個程式佔有的資源。

對於死鎖,有四種處理的策略:1. 忽略;2. 預防死鎖;3. 避免死鎖;4. 檢測死鎖並恢復。

死鎖預防

死鎖預防是指通過破壞死鎖產生的四個必要條件中的一個或多個,以避免發生死鎖。

  • 破壞互斥:不讓資源被一個程式獨佔,可通過假離線技術允許多個程式同時訪問資源;
  • 破壞擁有和請求:有兩種方案:
    • 已擁有資源的程式不能再去請求其他資源。一種實現方法是要求程式在開始執行前請求需要的所有資源。
    • 要求程式請求資源時,先暫時釋放其當前擁有的所有資源,再嘗試一次獲取所需的全部資源。
  • 破壞不可搶佔:有些資源可以通過虛擬化方式實現可搶佔;
  • 破壞迴圈等待:有兩種方案:
    • 一種方法是保證每個程式在任何時刻只能佔用一個資源,如果要請求另一個資源,必須先釋放第一個資源;
    • 另一種方法是將所有資源進行統一編號,程式可以在任何時刻請求資源,但要求程式必須按照順序請求資源。

死鎖避免

死鎖避免是利用一些事先已知的資訊,在分配資源時判斷是否會出現死鎖,如果不會出現死鎖才會分配資源。

而判斷是否會出現死鎖就是看是否能找到一個安全序列,系統能按照這個安全序列,也就是程式的推進順序為每個程式分配其所需資源,直到滿足每個程式所需的資源,使每個程式都能順序執行。

銀行家演算法

為實現銀行家演算法,程式在進入系統時,要求程式宣告需要資源的最大數目,但不能超過系統能提供的最大資源數目。當一個程式請求資源時,需要確定是否有足夠資源分配給該程式,如果有,再檢查在分配資源後,系統是否安全。

假定執行緒數量為 n,資源型別數量為 m,銀行家演算法的資料結構如下:

  • Max (總需求量):n*m 矩陣,表示程式 Ti 最多請求 Max[i, j] 個型別為 Rj 的資源;
  • Available (剩餘空閒量):長度為 m 的向量,表示當前有 Available[i] 個型別 Rj 的可用資源;
  • Allocation (已分配量):n*m 矩陣,表示程式 Ti 當前分配了 Allocation[i, j] 個型別為 Rj 的資源;
  • Need (未來需要量):n*m 矩陣,表示程式 Ti 未來需要 Need[i, j] 個型別為 Rj 資源;

可以得出它們滿足等式:Need[i, j] = Max[i, j] - Allocation[i, j]

銀行家演算法的核心部分,安全狀態的判斷如下:

  1. 建立長度為 m 的向量 Work,表示當前資源剩餘量,並進行初始化:Work = Avaiable;
  2. 在未執行的程式中尋找未來需要量 Need[i] 比當前可用量 Work 小的程式 Ti,如果找到則繼續執行 3,否則轉 4
  3. 執行 Work = Work + Allocation[j]; ,將資源分配給程式 Ti 執行完畢後,回收其資源。轉 2
  4. 如果資源可以分配給所有程式,則系統處於安全狀態;

如此完整的銀行家演算法如下:首先進行初始化,Request_i 表示程式 Ti 的資源請求向量,Request_i[j] 表示程式 Ti 請求資源 Rj 的例項。然後迴圈判斷:

  1. 如果 Request_i <= Need[i],轉到 2。否則拒絕資源請求,因為程式已經超過最大要求;
  2. 如果 Request_i <= Available,轉到 3。否則程式 Ti 必須等待,因為現在可用資源不足;
  3. 通過安全狀態判斷來確定是否分配資源給 Ti,如果安全則分配,否則拒絕 Ti 的資源請求。

死鎖檢測和恢復

可以允許系統進入死鎖狀態,但會維護一個系統的資源分配圖,定期呼叫死鎖檢測演算法來檢測途中是否存在死鎖,檢測到死鎖發生後,採取死鎖恢復演算法進行恢復。

死鎖檢測方法如下:

  • 在資源分配圖中,找到不會阻塞又不獨立的程式結點,使該程式獲得其所需資源並執行,執行完畢後,再釋放其所佔有的全部資源。也就是消去該程式結點的請求邊和分配邊。
  • 使用上面的演算法進行一系列簡化,若能消去所有邊,則表示不會出現死鎖,否則會出現死鎖。

在檢測死鎖時,可以採用兩種方法:

  • 搶佔資源。從一個或多個程式中搶佔資源分配給死鎖程式。
  • 終止程式。可以終止所有的死鎖程式;也可以按照某種順序,逐個終止程式,釋放其佔有資源,直到死鎖解除。

相關文章