操做系統 2009-09-24 16:48:58 閱讀767 評論1 字號:大中小 訂閱算法
1、要點提示安全
(1) 掌握死鎖的概念和產生死鎖的根本緣由。數據結構
(2) 理解產生死鎖的必要條件--如下四個條件同時具有:互斥條件、不可搶佔條件、佔有且申請條件、循環等待條件。併發
(3) 記住解決死鎖的通常方法,掌握死鎖的預防和死鎖的避免兩者的基本思想。性能
(4) 掌握死鎖的預防策略中資源有序分配策略。spa
(5) 理解進程安全序列的概念,理解死鎖與安全序列的關係。操作系統
(6) 瞭解銀行家算法。.net
(7) 瞭解資源分配圖。設計
(8) 瞭解死鎖的檢測及恢復的思想。htm
2、內容簡介
在計算機系統中有不少一次只能由一個進程使用的資源,如打印機,磁帶機,一個文件的I節點等。在多道程序設計環境中,若干進程每每要共享這類資源,並且一個進程所須要的資源不止一個。這樣,就會出現若干進程競爭有限資源,又推動順序不當,從而構成無限期循環等待的局面。這種狀態就是死鎖。系統發生死鎖現象不只浪費大量的系統資源,甚至致使整個系統崩潰,帶來災難性後果。因此,對於死鎖問題在理論上和技術上都必須給予高度重視。
死鎖是進程死鎖的簡稱,是由Dijkstra於1965年研究銀行家算法時首先提出來的。它是計算機操做系統乃至併發程序設計中最難處理的問題之一。實際上,死鎖問題不只在計算機系統中存在,在咱們平常生活中它也普遍存在。
1.什麼是死鎖
咱們先看看這樣一個生活中的例子:在一條河上有一座橋,橋面較窄,只能容納一輛汽車經過,沒法讓兩輛汽車並行。若是有兩輛汽車A和B分別由橋的兩端駛上該橋,則對於A車來講,它走過橋面左面的一段路(即佔有了橋的一部分資源),要想過橋還須等待B車讓出右邊的橋面,此時A車不能前進;對於B車來講,它走過橋面右邊的一段路(即佔有了橋的一部分資源),要想過橋還須等待A車讓出左邊的橋面,此時B車也不能前進。兩邊的車都不倒車,結果形成互相等待對方讓出橋面,可是誰也不讓路,就會無休止地等下去。這種現象就是死鎖。若是把汽車比作進程,橋面做爲資源,那麼上述問題就描述爲:進程A佔有資源R1,等待進程B佔有的資源Rr;進程B佔有資源Rr,等待進程A佔有的資源R1。並且資源R1和Rr只容許一個進程佔用,即:不容許兩個進程同時佔用。結果,兩個進程都不能繼續執行,若不採起其它措施,這種循環等待情況會無限期持續下去,就發生了進程死鎖。
在計算機系統中,涉及軟件,硬件資源均可能發生死鎖。例如:系統中只有一臺CD-ROM驅動器和一臺打印機,某一個進程佔有了CD-ROM驅動器,又申請打印機;另外一進程佔有了打印機,還申請CD-ROM。結果,兩個進程都被阻塞,永遠也不能自行解除。
所謂死鎖,是指多個進程循環等待它方佔有的資源而無限期地僵持下去的局面。很顯然,若是沒有外力的做用,那麼死鎖涉及到的各個進程都將永遠處於封鎖狀態。從上面的例子能夠看出,計算機系統產生死鎖的根本緣由就是資源有限且操做不當。即:一種緣由是系統提供的資源太少了,遠不能知足併發進程對資源的需求。這種競爭資源引發的死鎖是咱們要討論的核心。例如:消息是一種臨時性資源。某一時刻,進程A等待進程B發來的消息,進程B等待進程C發來的消息,而進程C又等待進程A發來的消息。消息未到,A,B,C三個進程均沒法向前推動,也會發生進程通訊上的死鎖。另外一種緣由是因爲進程推動順序不合適引起的死鎖。資源少也未必必定產生死鎖。就如同兩我的過獨木橋,若是兩我的都要先過,在獨木橋上僵持不願後退,必然會應競爭資源產生死鎖;可是,若是兩我的上橋前先看一看有無對方的人在橋上,當無對方的人在橋上時本身才上橋,那麼問題就解決了。因此,若是程序設計得不合理,形成進程推動的順序不當,也會出現死鎖。
從以上分析可見,若是在計算機系統中同時具有下面四個必要條件時,那麼會發生死鎖。換句話說,只要下面四個條件有一個不具有,系統就不會出現死鎖。
〈1〉互斥條件。即某個資源在一段時間內只能由一個進程佔有,不能同時被兩個或兩個以上的進程佔有。這種獨佔資源如CD-ROM驅動器,打印機等等,必須在佔有該資源的進程主動釋放它以後,其它進程才能佔有該資源。這是由資源自己的屬性所決定的。如獨木橋就是一種獨佔資源,兩方的人不能同時過橋。
〈2〉不可搶佔條件。進程所得到的資源在未使用完畢以前,資源申請者不能強行地從資源佔有者手中奪取資源,而只能由該資源的佔有者進程自行釋放。如過獨木橋的人不能強迫對方後退,也不能非法地將對方推下橋,必須是橋上的人本身過橋後空出橋面(即主動釋放佔有資源),對方的人才能過橋。
〈3〉佔有且申請條件。進程至少已經佔有一個資源,但又申請新的資源;因爲該資源已被另外進程佔有,此時該進程阻塞;可是,它在等待新資源之時,仍繼續佔用已佔有的資源。還以過獨木橋爲例,甲乙兩人在橋上相遇。甲走過一段橋面(即佔有了一些資源),還須要走其他的橋面(申請新的資源),但那部分橋面被乙佔有(乙走過一段橋面)。甲過不去,前進不能,又不後退;乙也處於一樣的情況。
〈4〉循環等待條件。存在一個進程等待序列{P1,P2,...,Pn},其中P1等待P2所佔有的某一資源,P2等待P3所佔有的某一源,......,而Pn等待P1所佔有的的某一資源,造成一個進程循環等待環。就像前面的過獨木橋問題,甲等待乙佔有的橋面,而乙又等待甲佔有的橋面,從而彼此循環等待。
上面咱們提到的這四個條件在死鎖時會同時發生。也就是說,只要有一個必要條件不知足,則死鎖就能夠排除。
前面介紹了死鎖發生時的四個必要條件,只要破壞這四個必要條件中的任意一個條件,死鎖就不會發生。這就爲咱們解決死鎖問題提供了可能。通常地,解決死鎖的方法分爲死鎖的預防,避免,檢測與恢復三種(注意:死鎖的檢測與恢復是一個方法)。咱們將在下面分別加以介紹。
死鎖的預防是保證系統不進入死鎖狀態的一種策略。它的基本思想是要求進程申請資源時遵循某種協議,從而打破產生死鎖的四個必要條件中的一個或幾個,保證系統不會進入死鎖狀態。
〈1〉打破互斥條件。即容許進程同時訪問某些資源。可是,有的資源是不容許被同時訪問的,像打印機等等,這是由資源自己的屬性所決定的。因此,這種辦法並沒有實用價值。
〈2〉打破不可搶佔條件。即容許進程強行從佔有者那裏奪取某些資源。就是說,當一個進程已佔有了某些資源,它又申請新的資源,但不能當即被知足時,它必須釋放所佔有的所有資源,之後再從新申請。它所釋放的資源能夠分配給其它進程。這就至關於該進程佔有的資源被隱蔽地強佔了。這種預防死鎖的方法實現起來困難,會下降系統性能。
〈3〉打破佔有且申請條件。能夠實行資源預先分配策略。即進程在運行前一次性地向系統申請它所須要的所有資源。若是某個進程所需的所有資源得不到知足,則不分配任何資源,此進程暫不運行。只有當系統可以知足當前進程的所有資源需求時,才一次性地將所申請的資源所有分配給該進程。因爲運行的進程已佔有了它所需的所有資源,因此不會發生佔有資源又申請資源的現象,所以不會發生死鎖。可是,這種策略也有以下缺點:
(1)在許多狀況下,一個進程在執行以前不可能知道它所須要的所有資源。這是因爲進程在執行時是動態的,不可預測的;
(2)資源利用率低。不管所分資源什麼時候用到,一個進程只有在佔有所需的所有資源後才能執行。即便有些資源最後才被該進程用到一次,但該進程在生存期間卻一直佔有它們,形成長期佔着不用的情況。這顯然是一種極大的資源浪費;
(3)下降了進程的併發性。由於資源有限,又加上存在浪費,能分配到所需所有資源的進程個數就必然少了。
(4)打破循環等待條件,實行資源有序分配策略。採用這種策略,即把資源事先分類編號,按號分配,使進程在申請,佔用資源時不會造成環路。全部進程對資源的請求必須嚴格按資源序號遞增的順序提出。進程佔用了小號資源,才能申請大號資源,就不會產生環路,從而預防了死鎖。這種策略與前面的策略相比,資源的利用率和系統吞吐量都有很大提升,可是也存在如下缺點:
(1)限制了進程對資源的請求,同時給系統中全部資源合理編號也是件困難事,並增長了系統開銷;
(2)爲了遵循按編號申請的次序,暫不使用的資源也須要提早申請,從而增長了進程對資源的佔用時間。
8.3 死鎖的避免
上面咱們講到的死鎖預防是排除死鎖的靜態策略,它使產生死鎖的四個必要條件不能同時具有,從而對進程申請資源的活動加以限制,以保證死鎖不會發生。下面咱們介紹排除死鎖的動態策略--死鎖的避免,它不限制進程有關申請資源的命令,而是對進程所發出的每個申請資源命令加以動態地檢查,並根據檢查結果決定是否進行資源分配。就是說,在資源分配過程當中若預測有發生死鎖的可能性,則加以免。這種方法的關鍵是肯定資源分配的安全性。
1.安全序列
咱們首先引入安全序列的定義:所謂系統是安全的,是指系統中的全部進程可以按照某一種次序分配資源,而且依次地運行完畢,這種進程序列{P1,P2,...,Pn}就是安全序列。若是存在這樣一個安全序列,則系統是安全的;若是系統不存在這樣一個安全序列,則系統是不安全的。
安全序列{P1,P2,...,Pn}是這樣組成的:若對於每個進程Pi,它須要的附加資源能夠被系統中當前可用資源加上全部進程Pj當前佔有資源之和所知足,則{P1,P2,...,Pn}爲一個安全序列,這時系統處於安全狀態,不會進入死鎖狀態。
雖然存在安全序列時必定不會有死鎖發生,可是系統進入不安全狀態(四個死鎖的必要條件同時發生)也未必會產生死鎖。固然,產生死鎖後,系統必定處於不安全狀態。
2.銀行家算法
這是一個著名的避免死鎖的算法,是由Dijstra首先提出來並加以解決的。
[背景知識]
一個銀行家如何將必定數目的資金安全地借給若干個客戶,使這些客戶既能借到錢完成要乾的事,同時銀行家又能收回所有資金而不至於破產,這就是銀行家問題。這個問題同操做系統中資源分配問題十分類似:銀行家就像一個操做系統,客戶就像運行的進程,銀行家的資金就是系統的資源。
[問題的描述]
一個銀行家擁有必定數量的資金,有若干個客戶要貸款。每一個客戶須在一開始就聲明他所需貸款的總額。若該客戶貸款總額不超過銀行家的資金總數,銀行家能夠接收客戶的要求。客戶貸款是以每次一個資金單位(如1萬RMB等)的方式進行的,客戶在借滿所需的所有單位款額以前可能會等待,但銀行家須保證這種等待是有限的,可完成的。
例如:有三個客戶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〉因爲要尋找一個安全序列,實際上增長了系統的開銷。
8.4 死鎖的檢測與恢復
通常來講,因爲操做系統有併發,共享以及隨機性等特色,經過預防和避免的手段達到排除死鎖的目的是很困難的。這須要較大的系統開銷,並且不能充分利用資源。爲此,一種簡便的方法是系統爲進程分配資源時,不採起任何限制性措施,可是提供了檢測和解脫死鎖的手段:能發現死鎖並從死鎖狀態中恢復出來。所以,在實際的操做系統中每每採用死鎖的檢測與恢復方法來排除死鎖。 死鎖檢測與恢復是指系統設有專門的機構,當死鎖發生時,該機構可以檢測到死鎖發生的位置和緣由,並能經過外力破壞死鎖發生的必要條件,從而使得併發進程從死鎖狀態中恢復出來。 1.放大觀看>>)
圖中所示爲一個小的死鎖的例子。這時進程P1佔有資源R1而申請資源R2,進程P2佔有資源R2而申請資源R1,按循環等待條件,進程和資源造成了環路,因此係統是死鎖狀態。進程P1,P2是參與死鎖的進程。 下面咱們再來看一看死鎖檢測算法。算法使用的數據結構是以下這些: 佔有矩陣A:n*m階,其中n表示併發進程的個數,m表示系統的各種資源的個數,這個矩陣記錄了每個進程當前佔有各個資源類中資源的個數。 申請矩陣R:n*m階,其中n表示併發進程的個數,m表示系統的各種資源的個數,這個矩陣記錄了每個進程當前要完成工做須要申請的各個資源類中資源的個數。 空閒向量T:記錄當前m個資源類中空閒資源的個數。 完成向量F:布爾型向量值爲真(true)或假(false),記錄當前n個併發進程可否進行完。爲真即能進行完,爲假則不能進行完。 臨時向量W:開始時W:=T。 算法步驟: (1)W:=T, 對於全部的i=1,2,...,n, 若是A[i]=0,則F[i]:=true;不然,F[i]:=false (2)找知足下面條件的下標i: F[i]:=false而且R[i]〈=W 若是不存在知足上面的條件i,則轉到步驟(4)。 (3)W:=W+A[i] F[i]:=true 轉到步驟(2) (4)若是存在i,F[i]:=false,則系統處於死鎖狀態,且Pi進程參與了死鎖。什麼時候進行死鎖的檢測取決於死鎖發生的頻率。若是死鎖發生的頻率高,那麼死鎖檢測的頻率也要相應提升,這樣一方面能夠提升系統資源的利用率,一方面能夠避免更多的進程捲入死鎖。若是進程申請資源不能知足就馬上進行檢測,那麼每當死鎖造成時即能被發現,這和死鎖避免的算法相近,只是系統的開銷較大。爲了減少死鎖檢測帶來的系統開銷,通常採起每隔一段時間進行一次死鎖檢測,或者在CPU的利用率下降到某一數值時,進行死鎖的檢測。 2.死鎖的恢復 一旦在死鎖檢測時發現了死鎖,就要消除死鎖,使系統從死鎖狀態中恢復過來。 (1)最簡單,最經常使用的方法就是進行系統的從新啓動,不過這種方法代價很大,它意味着在這以前全部的進程已經完成的計算工做都將付之東流,包括參與死鎖的那些進程,以及未參與死鎖的進程。 (2)撤消進程,剝奪資源。終止參與死鎖的進程,收回它們佔有的資源,從而解除死鎖。這時又分兩種狀況:一次性撤消參與死鎖的所有進程,剝奪所有資源;或者逐步撤消參與死鎖的進程,逐步收回死鎖進程佔有的資源。通常來講,選擇逐步撤消的進程時要按照必定的原則進行,目的是撤消那些代價最小的進程,好比按進程的優先級肯定進程的代價;考慮進程運行時的代價和與此進程相關的外部做業的代價等因素。 此外,還有進程回退策略,即讓參與死鎖的進程回退到沒有發生死鎖前某一點處,並由此點處繼續執行,以求再次執行時再也不發生死鎖。雖然這是個較理想的辦法,可是操做起來系統開銷極大,要有堆棧這樣的機構記錄進程的每一步變化,以便從此的回退,有時這是沒法作到的。 |