當兩個以上的運算單元,雙方都在等待對方停止執行,以獲取系統資源,但是沒有一方提前退出時,這種狀況,就稱為死鎖。在多工作業系統中,作業系統為了協調不同程序,能否獲取系統資源時,為了讓系統運作,就必須要解決這個問題。
程序死鎖是作業系統或軟體執行的一種狀態:在多工系統下,當乙個或多個程序等待系統資源,而資源又被程序本身或其它程序占用時,就形成了死鎖。
/**
* 死鎖範例
* 類的靜態變數是各個例項共享的,只分配一次,因此對這兩個變數的同步可能會導致死鎖
* 兩個執行緒在分別占有obj1和obj2後,一直等待obj2和obj1的鎖釋放,進入死鎖狀態不能繼續執行
* @author bingyue
* */
public class deadlock implements runnable
public static void main(string args)
@override
public void run() catch (interruptedexception e)
synchronized (obj2) } }
/*** 執行緒2的操作
*/if(flag==2) catch (interruptedexception e)
synchronized (obj1) } }
}}
如果系統中只有乙個程序,當然不會產生死鎖。如果每個程序僅需求一種系統資源,也不會產生死鎖。不過這只是理想狀態,在現實中是可遇不可求的。
死鎖的四個條件是:
禁止搶占:no preemption 程序已獲得的資源,在末使用完之前,不能強行剝奪。
持有和等待:hold and wait 乙個程序因請求資源而阻塞時,對已獲得的資源保持不放。
互斥:mutual exclusion 乙個資源每次只能被乙個程序使用。
迴圈等待:circular waiting 若干程序之間形成一種頭尾相接的迴圈等待資源關係。
預防死鎖就是至少破壞這四個條件其中一項,只要破壞這四個必要條件中的任意乙個條件,死鎖就不會發生。
(1)打破互斥條件。即允許程序同時訪問某些資源。但是,有的資源是不允許被同時訪問的,像印表機等等,這是由資源本身的屬性所決定的。所以,這種辦法並無實用價值。
(2)打破不可搶占條件。即允許程序強行從佔有者那裡奪取某些資源。就是說,當乙個程序已占有了某些資源,它又申請新的資源,但不能立即被滿足時,它必須釋放所占有的全部資源,以後再重新申請。它所釋放的資源可以分配給其它程序。這就相當於該程序占有的資源被隱蔽地強佔了。這種預防死鎖的方法實現起來困難,會降低系統效能。
(3)打破占有且申請條件。可以實行資源預先分配策略。即程序在執行前一次性地向系統申請它所需要的全部資源。如果某個程序所需的全部資源得不到滿足,則不分配任何資源,此程序暫不執行。只有當系統能夠滿足當前程序的全部資源需求時,才一次性地將所申請的資源全部分配給該程序。由於執行的程序已占有了它所需的全部資源,所以不會發生占有資源又申請資源的現象,因此不會發生死鎖。但是,這種策略也有如下缺點:
(4)打破迴圈等待條件,實行資源有序分配策略。採用這種策略,即把資源事先分類編號,按號分配,使程序在申請,占用資源時不會形成環路。所有程序對資源的請求必須嚴格按資源序號遞增的順序提出。程序占用了小號資源,才能申請大號資源,就不會產生環路,從而預防了死鎖。這種策略與前面的策略相比,資源的利用率和系統吞吐量都有很大提高,但是也存在以下缺點:
我們也可以嘗試迴避死鎖。因為在理論上,死鎖總是可能產生的,所以作業系統嘗試監視所有程序,使其沒有死鎖。
銀行家演算法(banker's algorithm)是乙個避免死鎖(deadlock)的著名演算法,是由艾茲格·迪傑斯特拉在2023年為t.h.e系統設計的一種避免死鎖產生的演算法。它以銀行借貸系統的分配策略為基礎,判斷並保證系統的安全執行。
在銀行中,客戶申請貸款的數量是有限的,每個客戶在第一次申請貸款時要宣告完成該專案所需的最大資金量,在滿足所有貸款要求時,客戶應及時歸還。銀行家在客戶申請的貸款數量不超過自己擁有的最大值時,都應盡量滿足客戶的需要。在這樣的描述中,銀行家就好比作業系統,資金就是資源,客戶就相當於要申請資源的程序。
1.安全序列
我們首先引入安全序列的定義:所謂系統是安全的,是指系統中的所有程序能夠按照某一種次序分配資源,並且依次地執行完畢,這種程序序列就是安全序列。如果存在這樣乙個安全序列,則系統是安全的;如果系統不存在這樣乙個安全序列,則系統是不安全的。
安全序列是這樣組成的:若對於每乙個程序pi,它需要的附加資源可以被系統中當前可用資源加上所有程序pj當前占有資源之和所滿足,則為乙個安全序列,這時系統處於安全狀態,不會進入死鎖狀態。
雖然存在安全序列時一定不會有死鎖發生,但是系統進入不安全狀態(四個死鎖的必要條件同時發生)也未必會產生死鎖。當然,產生死鎖後,系統一定處於不安全狀態。
2.銀行家演算法
這是乙個著名的避免死鎖的演算法,是由dijstra首先提出來並加以解決的。
乙個銀行家如何將一定數目的資金安全地借給若干個客戶,使這些客戶既能借到錢完成要幹的事,同時銀行家又能收回全部資金而不至於破產,這就是銀行家問題。這個問題同作業系統中資源分配問題十分相似:銀行家就像乙個作業系統,客戶就像執行的程序,銀行家的資金就是系統的資源。
乙個銀行家擁有一定數量的資金,有若干個客戶要貸款。每個客戶須在一開始就宣告他所需貸款的總額。若該客戶貸款總額不超過銀行家的資金總數,銀行家可以接收客戶的要求。客戶貸款是以每次乙個資金單位(如1萬rmb等)的方式進行的,客戶在借滿所需的全部單位款額之前可能會等待,但銀行家須保證這種等待是有限的,可完成的。
例如:有三個客戶c1,c2,c3,向銀行家借款,該銀行家的資金總額為10個資金單位,其中c1客戶要借9各資金單位,c2客戶要借3個資金單位,c3客戶要借8個資金單位,總計20個資金單位。某一時刻的狀態如圖所示。
c1 2(7)
c2 2(1)
c3 4(4)
餘額2c1 2(7)
c3 4(4)
餘額4c1 2(7)
餘額8餘額10
(a)(b)
(c)(d)
銀行家演算法示意
對於a圖的狀態,按照安全序列的要求,我們選的第乙個客戶應滿足該客戶所需的貸款小於等於銀行家當前所剩餘的錢款,可以看出只有c2客戶能被滿足:c2客戶需1個資金單位,小銀行家手中的2個資金單位,於是銀行家把1個資金單位借給c2客戶,使之完成工作並歸還所借的3個資金單位的錢,進入b圖。同理,銀行家把4個資金單位借給c3客戶,使其完成工作,在c圖中,只剩乙個客戶c1,它需7個資金單位,這時銀行家有8個資金單位,所以c1也能順利借到錢並完成工作。最後(見圖d)銀行家收回全部10個資金單位,保證不賠本。那麼客戶序列就是個安全序列,按照這個序列貸款,銀行家才是安全的。否則的話,若在圖b狀態時,銀行家把手中的4個資金單位借給了c1,則出現不安全狀態:這時c1,c3均不能完成工作,而銀行家手中又沒有錢了,系統陷入僵持局面,銀行家也不能收回投資。
綜上所述,銀行家演算法是從當前狀態出發,逐個按安全序列檢查各客戶誰能完成其工作,然後假定其完成工作且歸還全部貸款,再進而檢查下乙個能完成工作的客戶,......。如果所有客戶都能完成工作,則找到乙個安全序列,銀行家才是安全的。
從上面分析看出,銀行家演算法允許死鎖必要條件中的互斥條件,占有且申請條件,不可搶占條件的存在,這樣,它與預防死鎖的幾種方法相比較,限制條件少了,資源利用程度提高了。
這是該演算法的優點。其缺點是:
〈1〉這個演算法要求客戶數保持固定不變,這在多道程式系統中是難以做到的。
〈2〉這個演算法保證所有客戶在有限的時間內得到滿足,但實時客戶要求快速響應,所以要考慮這個因素。
〈3〉由於要尋找乙個安全序列,實際上增加了系統的開銷。
最簡單的消除死鎖的辦法是重啟系統。更好的辦法是終止乙個程序的執行。
同樣也可以把乙個或多個程序回滾到先前的某個狀態。如果乙個程序被多次回滾,遲遲不能占用必需的系統資源,可能會導致程序飢餓。
參考
死鎖的產生與解決
死鎖 所謂死鎖,是指在多道程式系統中,指兩個或兩個以上的程序在執行過程中,由於競爭資源或者由於彼此通訊而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。產生死鎖的主要原因有兩個 一是競爭資源 二是多道程式執行時,程序推進順序不合理。1.產生死鎖的四個必要條件 1 互斥條件 指程序對所分配到...
死鎖的產生與預防
在多執行緒中,為了保證執行緒安全,我們會使用互斥鎖,在某些程序或者執行緒中,使用了某些資源,為了完成任務,需要請求某些程序或執行緒所擁有的資源,從而形成了永久性等待狀態 1.互斥條件 乙個資源每次只能被乙個執行流執行 2.請求與保持 乙個資源想要獲取資源時阻塞,不會釋放已有資源 3.不可剝奪條件 乙...
死鎖的產生與避免
死鎖是指兩個或兩個以上的執行緒在執行過程中,因爭奪資源而造成的互相等待的現象,在無外力作用的情況下,這些執行緒會一直相互等待而無法繼續執行下去。死鎖的產生必須具備以下四個條件 互斥條件 指執行緒對己經獲取到的資源進行排它性使用 即該資源同時只由 乙個執行緒占用。請求並持有條件 指乙個執行緒己經持有了...