第三章 處理機的調度與死鎖
處理機調度的層次和調度算法的目標
調度的基本概念
在多道程序系統中,調度的實質是一種資源分配,處理機調度是對處理機資源進行分配。處理機調度算法是指根據處理機分配策略所規定的處理機分配算法。
在多道程序系統中,進程的數量遠遠多于處理機的個數,因此進程爭用處理機的情況在所難免。處理機調度是對處理機進行分配,即從就緒隊列中按照一定的算法(公平、高效)選擇一個進程并將處理機分配給它運行,以實現進程的并發執行。
處理機調度的層次
高級調度
高級調度又稱長程調度或作業調度,它調度的對象是作業。其主要功能是根據某種算法,決定將外存上處于后備隊列中的哪幾個作業調入內存,為它們創建進程、分配必要的資源,并將其放入就緒隊列。
高級調度主要用于多道批處理系統中,在分時系統和實時系統中不設置高級調度。高級調度的執行頻率較低,通常為幾分鐘一次。
低級調度
低級調度又稱為進程調度或短程調度,其所調度的對象是進程或內核級線程。其主要功能是根據某種算法決定就緒隊列中哪個進程應獲得處理機,并由分派程序將處理機分配給被選中的進程。
進程調度是最基本的一種調度,在多道批處理、分時系統和實時系統三種類型的OS中都必須設置這種調度。進程調度的頻率很高,一般幾十毫秒一次。
中級調度
中級調度又稱內存調度。引入中級調度的目的主要是提高內存的吞吐率和系統吞吐量。為此應把那些暫時不能運行的進程調至外存等待,此時進程的狀態稱為就緒駐外存狀態(或掛起狀態)。當它們已具備運行條件且內存又稍有空閑時,由中級調度來決定把外存上那些已具備運行條件的就緒進程再重新調入內存,并修改其狀態為就緒狀態,掛在就緒隊列上等待。中級調度實際上就是存儲器管理中的對換功能。
三級調度的聯系
- 高級調度為進程活動做準備,低級調度使進程正常活動起來,中級調度將暫時不能運行的進程掛起,中級調度處于高級調度和低級調度之間。
- 高級調度的次數較少,中級調度的次數略多,低級調度的頻率最高。
- 低級調度是最基本的,不可或缺。
處理機調度算法的目標
處理機調度算法的共同目標
- 資源利用率。為提高系統的資源利用率,應使系統中的處理機和其它所有資源都盡可能地保持忙碌狀態,其中最重要的處理機利用率的計算公式為:CPU的利用率 = CPU有效工作時間 / (CPU有效工作時間 + CPU空閑等待時間)。
- 公平性。公平性是指應使諸進程都獲得合理的CPU時間,不會發生進程饑餓現象。公平性是相對的,對相同類型的進程應獲得相同的服務;對于不同類型的進程,由于其緊急程度或重要性不同,則應提供不同的服務。
- 平衡性。由于系統中可能存在多種不同類型的進程(CPU密集型和I/O密集型),為使系統中的CPU和外設都能經常處于忙碌狀態,調度算法應盡可能保持系統資源使用的平衡性。
- 策略強制執行。對所制定的策略(如安全策略等),只要需要,就必須予以準確地執行。
批處理系統的目標
- 平均周轉周期短。周轉時間是指:作業從被提交給系統開始,到作業完成為止的這段時間間隔,計算公式為:周轉時間 = 作業完成時間 - 作業提交時間。平均周轉時間是指多個作業周轉時間的平均值,計算公式為:平均周轉時間 = (作業1的周轉時間 + 作業2的周轉時間 + ... + 作業n的周轉時間)。帶權周轉時間是指作業周轉時間與作業實際運行時間的比值,計算公式為:帶權周轉時間 = 作業周轉時間 / 作業實際運行時間。平均帶權周轉時間是指多個作業的帶權周轉時間的平均值,計算公式為:平均帶權周轉時間 = (作業1的帶權周轉時間 + ... + 作業n的帶權周轉時間) / n。作業的周轉時間包括四部分:1. 作業在外存后備隊列上等待作業調度的時間;2. 進程在就緒隊列上等待進程調度的時間;3. 進程在CPU上執行的時間;4. 進程等待I/O操作完成的時間。
- 系統吞吐量高。由于吞吐量是指單位時間內系統所完成的作業數,所以它與批處理作業的平均長度有關。若要提高系統吞吐量,應該更多地選擇短作業運行。
- 處理機利用率高。處理機的利用率是衡量系統性能的十分重要的指標,而調度方式又對處理機的利用率起著十分重要的作用。若要提高處理機利用率,應該盡量多地選擇計算量大的作業運行。
分時系統的目標
- 響應時間快。響應時間快是選擇分時系統中進程調度算法的重要準則。所謂響應時間是指用戶通過鍵盤提交一個請求開始,直到屏幕上顯示出處理結果為止的一段時間間隔,有三部分組成:1. 請求信息從鍵盤輸入開始,直至將其傳送至處理機的時間;2. 處理機對請求信息進行處理的時間;3. 將所形成的響應信息回送到終端顯示器的時間。
- 均衡性。所謂均衡性,是指系統響應時間的快慢應與用戶所請求服務的復雜性相適應。
實時系統的目標
- 截止時間的保證。所謂截止時間,是指某任務必須開始執行的最遲時間,或必須完成的最遲時間。對于實時系統而言,調度算法的一個主要目標是保證實時任務對截止時間的要求。
- 可預測性。在實時系統中,可預測性非常重要。
作業與作業調度
批處理系統中的作業
作業和作業步
- 作業:作業是一個比程序更廣泛的概念,它不僅包含了程序和數據,而且還應配有一份作業說明書,系統根據說明書對程序的運行進行控制。在批處理系統中,是以作業為基本單位從外存調入內存的。
- 作業步:通常,每個作業都必須經過若干個相互獨立又相互關聯的順序加工步驟才能得到結果,每一個加工步驟稱為作業步。各作業步之間相互聯系,往往是上一個作業步的輸出作為下一個作業步的輸入。
作業控制塊JCB
為了管理和調度作業,在多道批處理系統中,為每個作業設置一個作業控制塊JCB,它是作業在系統中存在的標志,其中保存了系統對作業進行管理和調度所需的全部信息,例如作業標識、用戶名稱、用戶賬號、作業類型(CPU繁忙型、I/O繁忙型、批量型、終端型)、作業狀態、調度信息(優先級、作業運行時間)、資源需求(預計運行時間、要求內存大小等)、資源使用情況等。
每當一個作業進入系統時,由“作業注冊”程序為該作業建立一個JCB,再根據作業類型放到相應的后備隊列中等待調度。調度程序根據一定的調度算法來調度它們,被調度的作業將被裝入內存。在作業運行期間,系統根據JCB中的信息和作業說明書對作業進行控制。當一個作業執行完畢后,系統負責回收分配給它的資源,并撤銷該JCB。
作業運行的三個階段和三種狀態
- 收容階段:操作員把作業輸入到硬盤上,再為該作業建立JCB,并把它放到后備隊列中。此時作業的狀態為后備狀態。
- 運行階段:作業被作業調度程序選中后,便為它分配必要的資源和建立進程,并將它放入就緒隊列。一個作業從第一次進入就緒狀態開始,直到運行結束前,在此期間都處于運行狀態。
- 完成階段:當作業運行完成或異常終止時,作業進入完成階段,此時作業的狀態為完成狀態。此時系統中的“終止作業”程序會回收已分配給該作業的JCB和所有資源,并將作業運行結果信息形成輸出文件后輸出。
作業調度的主要任務
作業調度的主要任務是根據JCB中的信息,檢查系統中的資源是否滿足作業對資源的需求,以及按照一定的調度算法,從外存的后備隊列中選取某些作業調入內存,并為它們創建進程、分配必要的資源,然后將新創建的進程排在就緒隊列上等待調度。因此也把作業調度稱為“接納調度”。在每次執行作業調度時,都需要決定接納多少個作業和接納哪些作業。
進程調度
調度的時機、切換與過程
進程調度和切換的程序是操作系統的內核程序。請求調度的事件發生后,才可能運行進程調度程序,調度了新的就緒進程后,才會進行進程間的切換。在實際設計中,操作系統的內核程序運行時,若發生了引起進程調度的因素,也不一定能夠馬上進行進程調度與切換。
不能進行進程調度與切換的原因有:
- 在處理中斷的過程中:中斷的處理過程復雜,在實現上很難做到進程切換。中斷處理是系統工作的一部分,邏輯上不屬于某一進程。
- 進程在操作系統內核程序臨界區中:進程進入臨界區后需要獨占式地訪問共享數據,理論上必須加鎖以防其他并行程序進入。在解鎖前不應切換到其他進程運行,以加快共享數據的釋放。
- 其他需要完全屏蔽中斷的原子操作過程中:如加鎖、解鎖、中斷現場保護、回復等原子操作。
若上述過程中發生了引起調度的條件,不能馬上進行進程的調度與切換,應置系統的請求調度標志,直到上述過程結束后再進行相應的調度與切換。
應該進行進程的調度與切換的情況如下:
- 發生引起調度條件且當前進程無法繼續執行時:此時可以馬上進行進程的調度與切換。若操作系統只在這種情況下進行進程調度,則是非剝奪調度。
- 中斷處理結束或自陷處理結束后,返回被中斷的進程的用戶態程序執行現場前:此時若有請求調度標志則可以馬上進行進程的調度與切換。若操作系統支持這種情況下的運行調度程序,則實現了剝奪方式的調度。
進程切換往往在調度完成后立刻發生。
進程調度方式
進程調度方式是指某個進程正在處理機上執行時,若有某個更為重要或緊迫的進程需要處理,即有更高優先權的進程進入就緒隊列,此時應該如何分配處理機。
進程調度通常有非剝奪調度方式和剝奪調度方式兩種方式。
非剝奪調度方式
又稱非搶占方式,是指當一個進程正在處理機上執行時,即使有某個更為重要或緊迫的進程進入就緒隊列,仍然讓正在執行的進程繼續執行,直到該進程完成或發生某種事件而進入阻塞狀態時,才把處理機分配給更為重要或緊迫的進程。在非剝奪調度方式下,一旦把CPU分配給一個進程,該進程就會保持CPU直到終止或轉換到等待態。
非剝奪調度方式適合大多數的批處理系統,但不能用于分時系統和大多數的實時系統。
剝奪調度方式
又稱搶占方式,是指當一個進程在處理機上執行時,若有某個更為重要或緊迫的進程需要使用處理機,則立即暫停正在執行的進程,將處理機分配給這個更為重要或緊迫的進程。
采用剝奪調度方式,對提高系統吞吐率和響應效率都有明顯的好處,但“剝奪”必須遵循一定的原則,主要有優先權、短進程優先、時間片原則等。
調度的基本準則
- CPU利用率:應盡可能使CPU處于“忙”狀態,使這一資源利用率最高。
- 系統吞吐量:表示單位時間內CPU完成作業的數量。
- 周轉時間:包括單個作業的周轉時間、平均周轉時間、帶權周轉時間、平均帶權周轉時間等。
- 等待時間:等待時間指進程處于等待處理機狀態的時間之和。
- 響應時間:響應時間指從用戶提交到系統首次產生響應所用的時間。
典型的調度算法
先來先服務(FCFS)
FCFS調度算法既可以用于作業調度,又可以用于進程調度。在作業調度中, 算法每次從后備隊列中選擇最先進入該隊列的一個或幾個作業,將它們調入內存,分配必要的資源,創建進程并放入就緒隊列。
在進程調度中,FCFS調度算法每次從就緒隊列中選擇最先進入該隊列的進程,將處理機分配給它,直到進程完成或因某種原因而阻塞才釋放處理機。
FCFS調度算法屬于不可剝奪算法。若一個長作業先到達系統,就會使后面許多短作業等待很長時間,因此它不能作為分時系統和實時系統的主要調度策略。但它常被結合在其它調度策略中使用,如在使用優先級作為調度策略的系統中,往往對多個具有相同優先級的進程按FCFS處理。
特點:
- 算法簡單,但效率低;
- 對長作業有利,對短作業不利;
- 有利于CPU繁忙型作業,不利于I/O繁忙型作業。
短作業優先(SJF)、短進程優先(SPF)
短作業優先調度算法是對短作業優先調度的算法。短作業優先算法從后備隊列中選擇一個或若干估計運行時間最短的進程,將它們調入內存執行;短進程優先算法從就緒隊列中選擇一個估計運行時間最短的進程,將處理機分配給它,直到完成或發生某事件而阻塞時,才釋放處理機。
特點:
- 對長作業不利:SJF調度算法中長作業的周轉時間會增加,長作業可能長期得不到調度(“饑餓”現象);
- 完全未考慮作業的緊迫程度:SJF調度算法不能保證緊迫性作業會被及時處理;
- 不一定真正做到短作業優先:作業的長短是根據用戶所提供的估計執行時間而定的,用戶有可能有意或無意地縮短其作業的估計運行時間,致使該算法不一定真正做到短作業優先;
- 平均等待時間、平均周轉時間最小。
優先級調度算法
優先級調度算法又可稱為優先權調度算法,既可以用于作業調度,又可以用于進程調度。該算法中的優先級用于描述作業的緊迫程度。在作業調度中,優先級調度算法每次從后備作業隊列中選擇優先級最高的一個或幾個作業,將它們調入內存,分配必要的資源,創建進程并放入就緒隊列。在進程調度中,優先級調度算法每次從就緒隊列中選擇優先級最高的進程,將處理機分配給它。
該算法按照更高優先級的進程是否搶占正在執行的進程可分為兩種:
- 非剝奪式優先級調度算法:當一個進程在處理機上運行時,即使有某個更為重要或緊迫的進程進入就緒隊列,仍然讓正在運行的進程繼續運行,直到由于其自身的原因而主動讓出處理機時(任務完成或等待事件),才把處理機分配給更為重要或緊迫的進程。
- 剝奪式優先級調度算法:當一個進程正在處理機上運行時,若有某個更為重要或緊迫的進程進入就緒隊列,則立即暫停正在運行的進程,將處理機分配給更為重要或緊迫的進程。
根據進程的優先級是否改變,可將進程的優先級分為以下兩種:
- 靜態優先級:優先級是在創建進程時確定的,且在進程的整個運行期間保持不變。確定靜態優先級主要依據是進程類型、進程對資源的要求、用戶要求。
- 動態優先級:在進程運行過程中,根據進程情況的變化動態調整優先級。動態調整優先級的主要依據有進程占有CPU時間的長短、就緒進程等待CPU時間的長短。
一般來說,進程優先級的設置可以參照以下原則:
- 系統進程 > 用戶進程;
- 交互型進程 > 非交互型進程(前臺進程 > 后臺進程);
- I/O型進程 > 計算型進程。
高相應比優先調度算法
高響應比優先調度算法主要用于作業調度,是對FCFS調度算法和SJF調度算法的一種綜合平衡,同時考慮了每個作業的等待事件和估計的運行時間。在每次進行作業調度時,先計算后備隊列中每個作業的響應比,從中選出響應比最高的作業投入運行。
響應比的計算公式為:響應比Rp = (等待時間 + 要求服務時間)/ 要求服務時間
特征:
- 作業的等待時間相同時,要求服務時間越短,響應比越高,有利于短作業。
- 要求服務時間相同時,作業的響應比由其等待時間決定,等待時間越長,響應比越高,因而它實現的是先來先服務。
- 對于長作業,作業的響應比可隨等待時間的增加而增長,等待時間足夠長時,其響應比可以升到很高。因此,該調度算法解決了SJF調度算法中長作業的“饑餓”問題。
時間片輪轉調度算法
時間片輪轉調度算法主要用于分時系統。系統將所有就緒進程按到達時間的先后次序排成一個隊列,進程調度程序總是選擇就緒隊列中的第一個進程執行,即先來先服務原則,但僅能運行一個時間片(如100ms)。在使用完一個時間片后,即使進程未完成其運行,它也必須釋放處理機給下一個就緒的進程,而被剝奪處理機的進程返回就緒隊列的末尾重新排隊,等候再次運行。
時間片的大小對性能影響很大。若時間片足夠大以至于所有進程都能在一個時間片內執行完畢,則該算法就退化為先來先服務調度算法;若時間片很小,則處理機將在進程間過于頻繁地切換,使處理機的開銷增大,而真正用于運行用戶進程的時間將減少。
時間片的長短通常由以下因素確定:
- 系統的響應時間;
- 就緒隊列中的進程數;
- 系統的處理能力。
多級反饋隊列調度算法(融合了前幾種算法的優點)
多級反饋隊列調度算法是時間片輪轉調度算法和優先級調度算法的綜合與發展。多級反饋隊列調度算法可以兼顧多方面的系統目標,如為提高系統吞吐量和縮短平均周轉時間而照顧短進程;為獲得較好的I/O設備利用率和縮短響應時間而照顧I/O型進程;不必事先估計進程的執行時間。
該算法的實現思想如下:
- 設置多個優先級不同的就緒隊列,其中第一級隊列的優先級最高,第二級隊列次之,其余隊列的優先級逐次降低。
- 賦予各個隊列中進程執行的時間片大小各不相同。在優先級越高的隊列中,每個進程的運行時間片越小。例如,第二級隊列的時間片要比第一級隊列的時間片長1倍,第i + 1級隊列的時間片要比第i級隊列的時間片長1倍。
- 一個新進程進入內存后,首先將它放入第1級隊列的末尾,按FCFS原則排隊等待調度。當輪到該進程執行時,如它能在該時間片內執行完成,便可準備撤離系統;若未執行完成,調度程序便將該進程轉入第二級隊列的末尾,再同樣按照FCFS原則等待調度。若它在第二級隊列中運行一個時間片后仍未完成,則再以同樣的方式放入第三級隊列。以此類推,當一個長進程從第一級隊列依次降級到第n級隊列后,在第n級隊列中采用時間片輪轉的方式運行。
- 僅當第1~(i - 1)級隊列為空時,調度程序才調度第i級隊列中的進程運行;若處理機正在執行第i級隊列中的進程,這時又有新的進程進入優先級較高的隊列,則此時新進程將搶占正在運行的進程的處理機,即由調度程序把正在運行的進程放回第i級隊列的隊尾,把處理機分配給新到的優先級更高的進程。
優點:
- 終端型作業用戶:短作業優先;
- 短批處理作業用戶:周轉時間短;
- 長批處理作業用戶:經過前面幾個隊列得到部分執行,不會長期得不到處理。
死鎖
死鎖的概念
死鎖是指多個進程因競爭資源而造成的一種僵局(互相等待),若無外力作用,這些進程都將無法向前推進。
死鎖產生的原因
- 系統資源的競爭:系統中擁有的不可剝奪資源(如打印機、磁帶機等)因其數量不足以滿足多個進程運行的需要,使得進程在運行過程中會因爭奪資源而陷入僵局。注:對可剝奪的資源的競爭不會產生死鎖。
- 進程推進順序非法:進程在運行過程中,請求和釋放資源的順序不當也同樣會導致死鎖。信號量使用不當也會造成死鎖(進程因等待對方的資源而產生死鎖)。
死鎖產生的四個必要條件
- 互斥條件:進程要求對所分配的資源(如打印機)進行排他性控制,即在一段時間內某資源僅為一個進程占有。此時若有其他進程請求該資源,則請求資源的進程只能等待。
- 不剝奪條件:進程所獲得的資源在未使用完之前不能被剝奪,即資源只能由獲得該資源的進程自己來釋放(只能是主動釋放)。
- 請求并保持條件:進程已經保持了至少一個資源,但又提出了新的資源請求,而該資源已經被其他進程占有,此時請求進程被阻塞,但對自己已獲得的資源保持不放。
- 循環等待條件:存在一種進程資源的循環等待鏈,鏈中的每個進程已獲得的資源同時被鏈中下一個進程所請求,即存在一個處于等待態的進程集合{P1, P2, ..., Pn},其中Pi等待的資源被Pi+1(i = 0, 1, ..., n - 1)占有,Pn等待的資源被P0所占有。注:資源分配圖含圈而系統又不一定有死鎖的原因是同類資源數大于1。但若系統中每類資源都只有一個,則資源分配圖含圈就變成了系統含有死鎖的充分必要條件。
死鎖的處理策略
為使系統不發生死鎖,必須破壞死鎖的四個必要條件之一,或允許死鎖產生,但當死鎖發生時能檢測出死鎖,并有能力實現恢復。
死鎖預防
設置某些限制條件,破壞產生死鎖的四個必要條件中的一個或幾個,以防止發生死鎖。
避免死鎖
在資源的動態分配過程中,用某種方法防止系統進入不安全狀態,從而避免死鎖。
死鎖的檢測及解除
無需采取任何限制性措施,允許進程在運行的過程中發生死鎖,通過系統的檢測機構及時地檢測出死鎖的發生,然后采取某種措施解除死鎖。
死鎖的預防和避免都屬于事先預防策略,預防死鎖的限制條件比較嚴格,實現起來較為簡單,但往往導致系統的效率低,資源利用率低;避免死鎖的限制條件比較寬松,資源分配后需要通過算法來判斷是否進入不安全狀態,實現起來比較復雜。
死鎖的幾種處理策略如下:
資源分配策略 | 各種可能模式 | 主要優點 | 主要缺點 | |
---|---|---|---|---|
死鎖預防 | 保守,寧可資源閑置 | 一次請求所有資源,資源剝奪,資源按序分配 | 適用于突發式處理的進程,不必進行剝奪 | 效率低,進程初始化時間延長;剝奪次數過多,不便靈活申請資源 |
死鎖避免 | 是“預防”和“檢測”的折中(在運行時判斷是否可能死鎖) | 尋找可能的安全允許順序 | 不必進行剝奪 | 必須知道將來的資源需求;進程不能被長時間阻塞 |
死鎖檢測 | 寬松,只要允許就分配資源 | 定期檢查死鎖是否已經發生 | 不延長進程初始化時間,允許對死鎖進行現場處理 | 通過剝奪解除死鎖,造成損失 |
死鎖預防
防止死鎖的發生只需要破壞死鎖產生的4個必要條件的其中之一即可。
破壞互斥條件
特點:把只能互斥使用的資源改造成允許共享使用,則系統就不會進入死鎖狀態。如操作系統使用SPOOLing技術把獨占設備在邏輯上改造成共享設備。
缺點:并不是所有的資源都可以改造成可以共享使用的資源,并且為了系統安全,很多地方還必須保持這種互斥性。因此,很多時候都無法破壞這種互斥條件。
破壞不剝奪條件
特點:
- 方案一:當一個已保持了某些不可剝奪資源的進程請求新的資源而得不到滿足時,它必須釋放已經持有的全部資源,待以后需要時再重新申請。也就是說,一個進程已占有的資源會被暫時釋放,或者說是被剝奪,從而破壞了互斥條件。
- 方案二:當某個進程需要的資源被其他進程所占有的時候,可以由操作系統協助,將想要的資源強行剝奪。這種方案一般需要考慮進程的優先級。
缺點:
- 實現起來比較復雜;
- 釋放已獲得的資源可能會造成前一階段工作的失效,因此這種方法一般只適用于狀態易于保存和恢復的資源,如CPU;
- 反復地申請和釋放資源會增加系統的開銷,降低系統的吞吐量;
- 若采用方案一,意味著只要暫時得不到某個資源,之前獲得的那些資源就必須放棄,以后再重新申請。如果這種情況一直發生,就可能導致進程饑餓。
破壞請求并保持條件
特點:可采用靜態分配方法,即進程運行之前一次申請完它所需要的全部資源,在它的資源尚未得到滿足前,不把它投入運行。一旦投入運行,這些資源就一直歸它所有,不再提出申請其他資源的請求。這種方法實現起來簡單。
缺點:有些資源可能只需要使用很短的時間,因此如果進程的整個運行期間都一直保持著所有資源,就會造成嚴重的資源浪費,資源利用率極低。另外,該策略也有可能導致某些進程饑餓。
破壞循環等待條件
特點:采用順序資源分配法,首先給系統中的資源編號,規定每個進程都必須按照編號遞增的順序請求資源,同類資源一次申請完。也就是說,只要進程提出申請分配資源Ri,則該進程在以后的資源申請中就只能申請編號大于Ri的資源(一個進程只有已占有小編號的資源時,才有資格申請更大編號的資源)。按此規則,已持有更大編號資源的進程不可能逆向地申請小編號的資源,從而就不會產生循環等待現象。
缺點:
- 不方便增加新類型的設備,因為可能需要重新分配所有的編號;
- 進程實際使用資源的順序可能和編號遞增順序不一致,會導致資源的浪費;
- 必須按照規定次序申請資源,必然會給用戶的編程帶來麻煩。
死鎖避免
系統安全狀態
所謂安全序列,就是指如果系統按照這種序列分配資源,則每個進程都能順利完成。只要找出一個安全序列,系統就是安全狀態。安全序列可能有多個。
如果分配了資源之后,系統找不到安全序列,則系統就進入了不安全狀態。這就意味著之后可能所有進程都無法順利執行下去。當然,如果有進程提前歸還了一些資源,那系統也有可能提前回到安全狀態。
如果系統處于安全狀態,那么就一定不會發生死鎖;如果系統進入不安全狀態,就可能發生死鎖(處于不安全狀態未必就發生了死鎖,但發生死鎖時系統一定處于不安全狀態)。因此可以在資源分配前預先判斷這次分配是否會導致系統進入不安全狀態,以此決定是否答應資源分配請求。
銀行家算法
設Requesti是進程Pi的請求向量,Requesti[j] = K表示進程Pi需要j類資源K個。當Pi發出資源請求后,系統按照如下步驟進行檢查:
- 若Requesti[j] <= Need[i, j],則轉向步驟2,否則認為出錯,因為它所需要的資源數已超過它所宣布的最大值。
- 若Requesti[j] <= Available[j],則轉向步驟3,否則表示尚無足夠資源,Pi需等待;
- 系統試探著把資源分配給進程Pi,并修改下面數據結構中的數值:
Available = Available - Request; Allocation[i, j] = Allocation[i, j] + Requesti[j]; Need[i, j] = Need[i, j] - Requesti[j]
; - 系統執行安全性算法,檢查此次資源分配后系統是否處于安全狀態。若安全,才正式將資源分配給Pi;若不安全,則將本次的試探分配作廢,恢復原來的資源分配狀態,讓進程Pi等待。
安全性算法描述如下:
- 初始時安全序列為空;
- 從Need矩陣中找出符合下面條件的行:該行對應的進程不在安全序列中,而且該行小于等于Work向量。找到后,把對應的進程加入安全序列;若找不到,則執行步驟4;
- 進程Pi進入安全序列后,可順利執行,直至完成,并釋放分配給它的資源,因此執行
Work = Work + Allocation[i]
,其中Allocation[i]表示進程Pi代表的在Allocation矩陣中對應的行,返回步驟2; - 若此時安全序列中已經有所有的進程,則系統處于安全狀態,否則系統處于不安全狀態。
死鎖的檢測與解除
若系統在為進程分配資源時不采取任何措施,則應該提供死鎖檢測與解除的手段。
資源分配圖
系統死鎖可用資源分配圖描述。如下圖所示,圓圈代表一個進程,框代表一類資源,由于一種資源可能有多個,所以用框中的一個圓代表一類資源中的一個資源。從進程到資源的有向邊稱為請求邊,表示該進程申請一個單位的該類資源;從資源到進程的邊稱為分配邊,表示該類資源已經有一個資源分配給了該進程。
死鎖定理
通過簡化資源分配圖可以檢測系統狀態S是否為死鎖狀態。簡化方法如下:
- 在資源分配圖中找出既不阻塞又不是孤點的進程Pi(即找出一條有向邊與它相連,且該有向邊對應資源的申請數量小于等于系統中已有的空閑資源數量。若所有連接該進程的邊均滿足上述條件,則這個進程能繼續運行直至完成,然后釋放它所占有的全部資源)。消去它所有的請求邊和分配邊,使之成為孤立的結點。
- 進程Pi所釋放的資源可以喚醒某些因等待這些資源而阻塞的進程,原來的阻塞進程可能變為非阻塞進程。根據1中的方法進行一系列簡化后,若能消去圖中所有的邊,則稱該圖是可完全簡化的。S為死鎖的條件是當且僅當S狀態的資源分配圖是不可完全簡化的,該條件稱為死鎖定理。
死鎖的解除
- 資源剝奪法:掛起某些死鎖進程,并搶占它們的資源,將這些資源分配給其他的死鎖進程,但應防止被掛起的進程長時間得不到資源而處于饑餓狀態;
- 撤銷進程法:強制撤銷部分甚至全部死鎖進程并剝奪它們的資源。撤銷的原則可以按進程優先級和撤銷進程代價的高低進行;
- 進程回退法:讓一個或多個進程回退到足以避免死鎖的地步,進程回退時自愿釋放資源而非被剝奪。這就要求系統記錄進程信息,并設置還原點。