所有申請的資源都被其他等待程序占有,那麼該等待程序有可能在無法改變其狀态,這種情況稱為死鎖(deadlock)。
程序在使用資源之前必須先申請資源,在使用資源之後要釋放資源。程序所申請的資源數量不能超過系統所有資源的總量。
在正常操作模式下,程序隻能按如下順序使用資源:
①申請:如果申請不能立即被允許,那麼申請程序必須等待,直到它獲得該資源為止。
②使用:程序對資源進行操作。
③釋放:程序釋放資源
資源的申請與釋放為系統調用。其他資源的申請與釋放可以通過信号量的wait與signal操作或通過互斥鎖的擷取與釋放來完成。是以對于程序和線程的每次使用,作業系統會檢查以確定使用程序已經申請并獲得了資源。
系統表記錄了每個資源是否空閑或已被配置設定,配置設定給了哪個程序。如果程序正在申請的資源正在為其他程序所使用,那麼該程序會增加到該資源的等待隊列。
當一組程序的每個程序都在等待一個事件,而這個事件隻能由這一組程序的另一個程序所引起,那麼這組程序就處于死鎖狀态。
死鎖也可設計不同的資源類型。多線程可能因為競争共享資源而容易産生死鎖。
當出現死鎖時,程序永遠不能完成,并且系統資源被阻礙使用,阻止了其他作業開始執行。
如果在一個系統中下面四個條件同時滿足,那麼會引起死鎖。
(1) 互斥:至少有一個資源必須處于非共享模式,即一次隻有一個程序使用,如果另一個程序申請該資源,那麼申請程序必須等到該資源被釋放為止。
(2) 占有并等待:一個程序必須占有至少一個資源,并等待另一資源,而該資源為其他程序所占有。
(3) 非搶占:資源不能被搶占,即資源隻能在程序完成任務後自動釋放。
(4) 循環等待:有一組等待程序{p0,p1,p2,p3…,pn},p0等待的資源被p1等待,p1等待的資源被p2所占有,……,pn-1等待的資源為pn所占有,pn所等待的資源被p0所占有。
4個條件必須同時滿足才會出現死鎖,循環等待條件意味着占有并等待條件,這樣四個條件并不完全獨立。
死鎖問題可用稱為系統資源配置設定圖的有向圖進行更為精确地描述。
這種圖由一個節點集合V和一個邊集合E組成。節點集合V可以分成兩種類型的節點:
P={p1,p2,…,pn}(系統活動程序的集合)
R={r1,r2,…,rn}(系統所有資源的集合)
pi -> rj 表示程序pi已經申請了資源類型為rj的一個執行個體,稱為申請邊
rj->pi表示資源類型rj已經配置設定給程序pi,稱為配置設定邊
如一個配置設定圖的例子如下:

可以證明:
如果配置設定圖沒有環,那麼系統就沒有程序死鎖。如果配置設定圖有環,那麼可能存在死鎖。
如果每個類型隻有一個執行個體,環是死鎖存在的充分必要條件。過每個類型不止一個執行個體,環是死鎖的必要條件。
存在死鎖的資源配置設定圖:
存在環但是沒有死鎖的資源配置設定圖
有三種方法:
可使用協定以預防或避免死鎖,確定系統不會進入死鎖狀态。
可允許系統進入死鎖狀态,然後檢測它,并加以修複。
可忽略這個問題,認為死鎖不可能在系統内發生。
這裡第三種方法為絕大多數作業系統所用,是以應用程式開發人員需要自己來處理死鎖。
為了確定死鎖不會發生,系統可以采用死鎖預防或死鎖避免方案
死鎖預防(deadlock prevention)是一組方法,以確定至少一個必要條件不成立。這些方法通過限制如何申請資源的方法來預防死鎖。
死鎖避免(deadlock avoidance)要求作業系統事先得到有關程序申請資源和使用資源的額外資訊。有了這些額外資訊,系統可以确定:對于一個申請,程序是否應等待。為了确定目前申請是允許還是延遲,系統必須考慮可用資源,已經配置設定給每個程序的資源,每個程序将來申請和釋放的資源。
除此之外,系統還可以提供一個算法來檢查系統狀态來确定死鎖是否發生,并提供另一個算法來從死鎖中恢複。
預防死鎖的副作用是降低裝置的使用率和系統的吞吐率。
缺點是低裝置使用率和系統吞吐率。
出現死鎖有四個必要條件,隻要保證至少一個條件不成立,就能預防死鎖的發生。
對于非共享資源,必須要有互斥條件(如列印機)。另一方面,共享資源不要求互斥通路,是以不會涉及死鎖(如隻讀檔案)。
故通常不能通過否定互斥條件來預防死鎖,有的資源本身就是非共享的。
為了確定占有并等待條件不會在系統内出現,必須保證:當一個程序申請一個資源時,就不能占有其他資源
方法一:可以使用的協定是每個程序在執行前申請并獲得所有資源。通過要求申請資源的系統調用在所有其他系統調用之前進行。
方法二:允許程序在沒有資源時才可申請資源,一個程序可申請一些資源并使用它們,然而,在它申請更多其他資源之前,它必須釋放其現已配置設定的所有資源。
這兩種協定有兩個主要缺點:
第一,資源使用率(resource utilization)可能比較低,因為很多資源可能已配置設定,但長時間沒有被使用。
第二,可能發生饑餓。一個程序如需要多個常用資源,可能會永久等待,比如因為其所需要的資源中至少一個總是配置設定給其他的程序。
為確定這一條件不成立,可使用如下協定:
即可以搶占,如果一個程序占用資源并申請另一個不能立即配置設定的資源,那麼其現已配置設定的資源都可被搶占,即這些資源被隐式地釋放了。隻有當程序獲得其原有資源和所申請的新資源時,程序才可以重新執行。
或者說,如果一個程序申請一些資源,首先檢查是否可用,如果可用就配置設定它們,如果不可用,那麼檢查這些資源是否已配置設定給其他等待額外資源的程序。如果是就搶占這些資源,并配置設定給申請程序。如果資源不可用且也不可被其他等待程序占有,那麼申請程序必須等待。當一個程序處于等待時,如果其他程序申請其擁有的資源,那麼該程序部分資源可以被搶占。一個程序要重新執行,他必須配置設定到其所申請的資源,并恢複其在等待時被搶占的資源。
這個協定通常用于狀态可以儲存和恢複的資源,如cpu寄存器和記憶體,一般不适用其他資源,如列印機和錄音帶驅動器。
一個確定此條件不成立的方法是:對所有資源類型進行完全排序,且要求每個程序按遞增順序來申請資源。
設R={r1,r2,r3,…,rn}為資源類型的的集合。為每個資源類型配置設定一個唯一整數來允許比較兩個資源以确定其先後順序。可定義一個函數F:r -> n ,其中N是自然數集合,例如:
F(tape drive)=1
F(disk drive)=5
F(printer)=12
每個程序隻按照遞增順序申請資源,即一個程序開始可以申請任意數量的資源類型為Ri的執行個體。之後,當且僅當F(rj)> F(ri)時,該程序可以申請資源rj的執行個體。如果需要同一資源類型的多個執行個體,那麼對它們必須一起申請。
例如,對于以上給定函數,一個程序如果同時需要列印機和錄音帶驅動器,那麼就必須先申請錄音帶驅動器,再申請列印機。換句話說,要求當一個程序申請資源類型rj時,必須先釋放所有ri(F(ri)> F(rj))
可以使用反證法證明,使用這兩個協定,那麼循環等待就不可能成立。
設計一個完全排序或層析并不能防止死鎖,而是要靠應用程式員來按順序編寫程式。另外函數F應該根據系統内資源使用的正常順序來定義。例如,由于錄音帶通常在列印機之前使用,是以定義F(tape drive)< F(printer)較為合理。