程序管理
程序與執行緒
程序概念的引入
基本概念
-
併發與並行
- 順序執行
- 並行:兩個程式在同一時間度量下同時執行在不同的處理機上
- 併發:兩個活動在某一指定時刻,無論是在同一處理機還是不同處理機上,二者都處在各自的起點到終點之間的某一處。
-
程式的順序執行與特徵
- 順序性:按程式結構指定的次序執行
- 封閉性:獨佔全部資源,計算機狀態只由該程式的控制邏輯所決定
- 可再現性:初始條件相同則結果相同
-
程式的併發執行在時間上是重疊的:一個程式的第一條指令是在另一個程式的最後一條指令完成之前開始的
程式併發執行時的特徵:
-
間斷性:執行——暫停——執行
-
非封閉性:多個程式共享系統中的資源
-
不可再現性,因為發生了競爭:多個程序在讀寫同一個共享資料時結果依賴於它們執行的相對時間
競爭條件:多個程序併發訪問和操作同一資料,且執行結果與訪問的順序有關
-
Bernstein 條件
- 定義:R(Si):Si的讀子集,其值在Si中被引用的變數的集合
- W(Si):Si的寫子集,其值在Si中被改變的變數的集合
兩個程序S1和S2可併發,當且僅當以下條件同時成立:
![image-20240417150614485](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240417150614485.png)
沒有讀寫衝突和寫寫衝突。
![image-20240417150737429](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240417150737429.png)
Bernstein條件是判斷程式併發執行結果是否可再現的充分條件。
程序的定義
- 程序是程式的一次執行;
- 程序是可以和別的計算併發執行的計算。
- 程序可定義為一個資料結構,及能在其上進行操作的一個程式。
- 程序是一個程式及其資料在處理機上順序執行時所發生的活動。
- 程序是程式在一個資料集合上執行的過程,它是系統進行資源分配和排程的一個獨立單位。
程序的特徵
- 動態性:程序是程式的一次執行過程,,因建立而產 生,因排程而執行,因無資源而暫停,因撤消而消亡;而程式是靜態實體。
- 併發性
- 獨立性:程序是獨立執行的基本單位
- 非同步性:也叫制約性,程序之間相互制約,程序以各自獨立的不可預知的速度向前推進。
- 結構特徵:程式、資料、程序控制塊PCB
作業、程序與程式
- 程序是動態的,程式是靜態的。
- 程序是暫時的,程式是永久的。
- 作業通常包括程式、資料和操作說明書。
- 程序與程式的組成不同:程序的組成包括程式、資料和程序控制塊PCB。說明程式是程序的一部分,是程序的實體。
- 程序與程式的對應關係:透過多次執行,一個程式可以對應多個程序;透過呼叫關係,一個程序可包括多個程式。
- 一個作業可以劃分為若干個程序;每一個程序有其實體:程式和資料集合。
程序狀態與控制
程序控制的主要任務:建立和撤銷程序,以及實現程序的狀態轉換。由核心來實現
-
程序建立:
- 提交一個批處理作業
- 使用者登入
- 由OS建立,用以向一個使用者提供服務
- 由已存在的一程序建立
-
程序撤銷:
- 使用者退出登入
- 程序執行一箇中止服務的請求
- 出錯、失敗
- 正常結束
- 給定時限到
-
原語:由若干條指令所組成的指令序列,來實現某個特定的操作功能
- 指令序列執行時連續的
- 是作業系統的核心組成部分
- 必須在核心態下執行
- 不可中斷
-
建立原語:
fork
,exec
-
撤銷原語:
kill
Fork()
函式使用舉例
int main(){
pid_t fpid;
int count = 0;
fpid = fork();//建立了一個新程序,此時有兩個程序在執行
if(fpid<0)
printf("err in fork!");
else if(fpid == 0){//在子程序中,fork函式返回0
printf("I am the child process,my process id is %d",getpid());
count++;
}
else{//在父程序中,fork函式返回新建立子程序的程序ID
printf("I am the parent process ,my process id is %d",getpid());
count++;
}
printf("統計結果是:%d/n",count);
}
根據fork函式返回的值,可以判斷當前程序是父程序還是子程序。
fork
建立普通程序clone
建立執行緒kernel_thread
建立核心程序
程序的狀態
- 就緒狀態:程序已獲得除處理機(CPU)外的所有所需資源
- 執行狀態:佔用處理機資源
- 阻塞狀態:正在執行的程序,由於某種時間暫時無法執行,放棄處理機處於暫停狀態
![image-20240409143449602](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240409143449602.png)
程序控制塊PCB
作用:程序的建立和撤銷;作為程序的唯一標識
![程序控制塊內容](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240409144112425.png)
PCB的組織方式
- 線性表:不論程序狀態如何,將所有PCB連續地存放在記憶體的系統區。適用於程序數量不多的情況。
- 索引方式:系統按照程序的狀態分別建立就緒索引表、阻塞索引表等。
- 連結方式:系統按照程序的狀態將程序的PCB組成佇列,從而形成就緒佇列、阻塞佇列、執行佇列。
程序上下文切換vs陷入核心
程序上下文切換
一定會陷入核心。
- 通常由排程器執行
- 儲存程序執行斷點
- 切換記憶體對映
陷入/退出核心
不一定導致程序切換。
- CPU狀態改變
- 由中斷、異常、Trap指令引起
- 需要儲存執行現場
- 消耗相對程序上下文切換小很多
執行緒概念的引入
程序的不足:
-
程序在一個時間只能處理一個任務
-
如果程序在執行時阻塞,整個程序都無法繼續執行
在等待輸入時,即使程序中有些處理不依賴於 輸入資料,也將無法執行。
所以需要提出一種新的實體,滿足:
- 實體之間可以併發地執行
- 實體之間共享相同的地址空間(程序擁有各自獨立的地址空間)
實際上程序包含兩個概念:資源擁有者和可執行單元
現代作業系統將資源擁有者稱為程序,可執行單元稱為執行緒
執行緒:將資源與計算分離,提高併發效率(執行緒之間共享了資源,分別計算)
不適合多執行緒的情況:計算量大,CPU負載高。
程序與執行緒的區別
-
併發執行
- 多程序:多個程式可以併發執行,改善資源使用率
- 多執行緒:併發粒度更細,併發性更好→執行緒可以提高程序內的開發程度
-
執行緒間可以共享資源
- 程序的資源(執行緒共享的資源):虛擬地址空間、程序映像、處理機保護、檔案、IO
- 執行緒的私有資源:執行狀態、上下文(如程式計數器)、執行棧
-
系統開銷:
- 程序:建立/撤銷時需要分配/回收大量資源
- 執行緒:由於資源共享,減少了許多開銷。
引入執行緒的優勢:執行緒很輕量,容易建立、撤銷
![image-20240417171404153](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240417171404153.png)
執行緒的實現方式
使用者級執行緒
執行緒在使用者控制元件,透過library
模擬的thread
,不需要或僅需要極少的kernel
支援
- 使用者級執行緒庫的主要功能:建立和銷燬執行緒;執行緒之間傳遞訊息和資料;排程執行緒執行;儲存和恢復執行緒上下文
- 上下文切換比較快,因為不用更改
page table
等。 - 典型例子:java,POSIX
- 優點:
- 執行緒切換與核心無關
- 執行緒排程由應用決定,容易最佳化
- 可執行在任何作業系統上,只需要執行緒庫的支援。
- 不足:
- 很多系統呼叫會引起阻塞,核心會因此而阻塞所有相關概念的執行緒。
- 核心只能將處理器分配給程序,即使有多個處理器也無法實現一個程序中 多個執行緒的並行執行。
核心級執行緒(→多執行緒核心)
kernel有好幾個分身,一個分身可以用來處理一個事件。
對於處理非同步事件很有用,kernel可對每個非同步事件產生一個分身來操作。
- 典型例:Linux,Windows XP
- 優點
- 核心可以在多個處理器上排程一個程序的多個執行緒 實現同步並行執行。
- 阻塞發生線上程級別。
- 核心中一些處理可透過多執行緒實現。
- 缺點
- 一個程序中的執行緒,切換需要核心參與,執行緒的切換涉及兩個模式的切換:程序–程序;執行緒–執行緒。降低效率。(切換時需要陷入核心)
比較
- 核心級執行緒是OS核心可感知的,而使用者級執行緒 是OS核心不可感知的。
- 使用者級執行緒的建立、撤消和排程不需要OS核心 的支援,是在語言或使用者庫這一級處理的;而內 核級執行緒的建立、撤消和排程都需OS核心提供 支援,而且與程序的建立、撤消和排程大體是相 同的。
- 使用者級執行緒執行系統呼叫指令時將導致其所屬進 程的執行被暫停,而核心級執行緒執行系統呼叫指 令時,只導致該執行緒被暫停。
- 在只有使用者級執行緒的系統內,CPU排程還是以程序為單位,處於執行狀態的程序中的多個線 程,由使用者程式控制執行緒的輪換執行;在有核心級執行緒的系統內,CPU排程則以執行緒為單位 ,由OS的執行緒排程程式負責執行緒的排程。
- 使用者級執行緒的程式實體是執行在使用者態下的程式,而核心級執行緒的程式實體則是可以執行在任何狀態下的程式。
混合執行緒
有些系統同時支援使用者執行緒和核心執行緒,由此 產生了不同的多執行緒模型,即實現使用者級執行緒 和核心級執行緒的不同連線方式。
- Many-to-One:多對一
- One-to-One:一對一
- Many-to-Many:多對多
同步與互斥
基本概念
- 程序的三個特徵:併發、共享、不確定
- 臨界資源:一次僅允許一個程序訪問的資源
- 臨界區:每個程序中訪問臨界資源的程式碼稱為臨界區
程序互斥(間接制約關係)
- 兩個或兩個以上的程序,不能同時進入關於同一組共享資源的臨界區。
- 程序互斥是程序間發生的一種間接性作用,一般是程式不希望的
- 無法限制訪問者對資源的訪問順序,是無序訪問
程序同步(直接制約關係)
- 系統各程序之間能有效地共享資源和相互合作,從而使程式的執行具有可再現性。
- 程序同步時程序間一種刻意安排的直接制約關係
- 在互斥的基礎上,透過其它機制實現訪問者對資源的有序訪問。
臨界區管理應該滿足的條件
- 沒有程序在臨界區時,想進入臨界區的程序可以進入
- 任何兩個程序都不能同時進入臨界區
- 任何一個程序進入臨界區的請求應該在有限時間內得到滿足
- 當一個程序執行在臨界區外面時,不能妨礙其他程序進入臨界區
機制設計時應遵循的準則
- 空閒讓進:臨界資源處於空閒狀態,允許程序進入臨界區
- 忙則等待:臨界區有正在執行的程序,所有其他程序則不可以進入臨界區。
- 有限等待:對要求訪問臨界區的程序,應保證在有限時間內進入自己的臨界區,避免死等。 (受惠的是程序自己)
- 讓權等待:當其他程序(長時間)不能進入自己的臨界區時,應立即釋放處理機,儘量避免忙等。(受惠的是其他程序)
忙等待:可以與自旋鎖、輪詢等同,程序不斷申請進入臨界區,直到被允許。像 while(judge)
讓權等待:程序申請進入臨界區,不被允許則睡眠(阻塞、等待)。像 sleep()
睡眠是阻塞的一種方式,睡眠的程序會sleep一段時間,醒來後繼續執行。
兩者比較,忙等待一直佔用CPU,一直申請進入臨界區操作,程序處於執行態;
讓權等待申請一次後被拒,則主動讓出CPU,程序處於阻塞態
基於忙等待的互斥方法
- 軟體方法
- 硬體方案1:中斷遮蔽
- 執行“關中斷“指令,進入臨界區操作。(不允許被其他指令中斷)
- 退出臨界區之前,執行“開中斷“指令
- 使用範圍:核心程序,不適合多CPU系統
- 會帶來很大的效能損失
- 硬體方案2:
test and set
指令,如自旋鎖Spinlocks
共性問題
- 忙等待:浪費CPU時間
- 優先順序反轉:
- 低優先順序程序先進入臨界區,高優先順序程序一直忙等待;但是優先排程高優先順序程序執行,導致兩個程序都不會執行下去。
- 如果使用使用者級執行緒,低優先順序執行緒不會被高優先 級執行緒搶佔,因為搶佔發生在程序級別。但是對於核心級執行緒的實現,這個是可能發生的。
基於訊號量的同步方法
解決忙等待的方法:將忙等待變為阻塞。可以使用原語:Sleep和Wakeup
顯然Wakeup的呼叫需要一個引數:被喚醒的程序ID
訊號量
- 訊號量使用一個整型變數來累計喚醒次數;
- 程式對其訪問是原子操作,且只允許對它進行P操作和V操作
訊號量的定義
訊號量是一個確定的二元組(s,q),其中:
- s是一個具有非負初值的整型變數。發出P操作時,該值可等於立即執行的程序數量;當s<=0時,發出P操作後的程序被阻塞,|s|是被阻塞的程序數
- q是一個初始狀態為空的佇列。發出P操作時,有程序被阻塞時就會進入此佇列。
訊號量的分類
-
二元訊號量&一般訊號量
-
二元訊號量:取指僅為0或1,主要用於實現互斥
應用時應該注意:
-
每個程序中的PV操作必須成對出現,先P操作進入臨界區,再V操作出臨界區。
-
PV操作儘量緊靠頭尾部。
-
互斥訊號量初始值一般為1。
-
-
一般訊號量:初始值為可用物理資源的總數,可用於程序的協作同步。
-
-
強訊號量&弱訊號量
- 強訊號量:程序從被阻塞佇列中釋放時採用FIFO,不會出現“飢餓”(某個程序長時間被阻塞)
- 弱訊號量:沒有規定程序從阻塞佇列中的移除順序,可能出現“飢餓”。
一般訊號量的結構
![image-20240418104935161](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240418104935161.png)
訊號量的操作
-
一個訊號量可能被初始化為一個非負整數
-
P操作使訊號量
-1
。若值<0
(表示此類資源已被分配完畢),則執行P操作的程序被阻塞,否則程序繼續執行 -
V操作使訊號量
+1
,若值<=0
(表示此時仍然有程序在等待這類資源),則被P操作阻塞的程序解除阻塞都是先減/加,再判斷範圍。
訊號量的應用
-
互斥(一P一V):用初始值為1的訊號量來實現程序間的互斥。一個程序在進入臨界區之前執行P操作,退出臨界區時執行V操作。
-
有限併發:有n個程序併發執行一個函式/資源。使用一個初始值為c(c>=n)的訊號量可以實現併發。
實際上有多少資源,就把初始值設為多少。申請資源時呼叫P,釋放資源是呼叫V。
-
程序同步(先V後P ):程序P2想要執行⼀個a2操作時,它只在程序P1執行完a1後,才會執行a2操作。
將訊號量初始值設為0,P1執行a1操作後,執行一個V操作;P2執行a2操作前,執行一個P操作。
如圖中理解,程序同步的“前V”實際上是先產生某種後續需要的資源,所以初始為0;“後P”是對產生資源的使用。
-
前驅關係:(實際上是若干個程序同步)
PV操作的優缺點
- 優點:簡單,可以解決任何同步互斥問題。
- 缺點:不夠安全;使用不當會出現死鎖;遇到複雜同步互斥問題時實現複雜。
訊號量集機制
-
AND型
將程序需要的所有共享資源一次全部分配給它,程序使用完後再一起釋放
-
一般訊號量集
程序對訊號量Si的測試值為ti,即Si >= ti,表示資源數量低於ti時,便不予分配;
佔用值為di,用於訊號量的增減,即Si = Si - di和Si = Si + di 。
管程
管程是一種高階同步機制;管道是單獨構成一種獨立的檔案系統,並且只存在在記憶體中。
定義:一個管程定義了一個資料結構,和能為併發程序所執行的一組操作,這組操作能同步程序和改變管程中的資料。
組成:
- 名稱
- 區域性與管程內部的共享資料結構說明
- 對該資料結構進行操作的一組互斥執行的過程
- 對區域性於管程內部的共享資料設定初始值的語句
條件變數:(與訊號量的區別)
為了區別等待的不同原因,管程引入了條件變數。不同的條件變數對應不同原因的程序阻塞等待佇列。
- 條件變數的值不可增減;
- wait操作一定會阻塞當前程序
- 如果沒有等待的程序,signal將會丟失。
- 訪問條件變數必須擁有管程的鎖。
Hoare管程:
- 入口等待佇列、緊急等待佇列
- x.wait:先判斷緊急等待佇列,再判斷入口等待佇列
- x.signal:若x佇列為空則相當於空操作;否則喚醒第一個等待者,執行x.signal()操作的程序排入緊急等待佇列的尾部。
程序通訊IPC
- 低階通訊:只能傳遞狀態和整數值(控制資訊),包括程序互斥和同步所採用的訊號量和管程機制。缺點:
- 傳送資訊量小,效率低。
- 程式設計複雜:使用者直接實現通訊的細節,程式設計複雜。
- 相同地址空間:屬於同一個程序的多個執行緒/共享地址空間的多個程序
- 高階通訊:適用於分散式系統,基於共享記憶體的多處理機系統、單處理機系統,能傳送任何熟練的資料,可以解決程序的同步問題和通訊問題。主要包括三類:管道、共享記憶體、訊息系統。
管道:
- 無名管道Pipe:只支援親緣關係程序;資料只能向一個方向流動;單獨構成一種獨立的檔案系統,只存在於記憶體當中。寫入的內容新增在管道末尾、從頭部讀出。
- 有名管道FIFO:沒有限制;嚴格先進先出。
訊息傳遞
- 使用兩個通訊原語:send和receive
- 主要解決訊息丟失、延遲問題
共享記憶體:
- 共享記憶體的意義:同一塊實體記憶體被對映到程序A、B各自的程序地址空間。
- 共享記憶體可以同時讀但不能同時寫,所以需要同步機制約束
- 通訊效率高,是最有用也是最快的。
套接字
可以用於不同機器之間的程序通訊,也可以用於本機的兩程序通訊。
經典同步互斥問題
生產者—消費者問題
若干程序透過有限的共享緩衝區交換資料,其中生產者程序不斷寫入,消費者程序不斷取出(寫操作);
共享緩衝區共有N個;
任何時刻只能有一個程序可對共享緩衝區進行操作。
- 隱含條件:
- 消費者和生產者數量不固定;
- 消費者和生產者不能同時使用緩衝區
- 行為關係:
- 生產者之間:互斥
- 消費者之間:互斥
- 生產者和消費者之間:互斥(放/取產品);同步(放置——取出)
PV操作解決
-
訊號量設定:
semaphore mutex = 1
//互斥semaphore empty = N
//空閒數量semaphore full = 0
//產品數量 -
兩個V交換順序對語義無影響,但會降低效率。
Sleep和Wakeup原語解決
讀者—寫者問題
哲學家進餐問題
排程
CPU排程的任務是控制、協調多個程序對CPU的競爭。
排程的型別:
- 高階排程:又稱“作業排程”,從使用者角度,一次提交若干個作業,對每個作業進行排程。
- 中級排程:又稱“內外存交換”,從儲存器資源管理的角度,將程序的部分或全部換出到外存上,將當前所需的部分換入到記憶體。
- 低階排程:又稱”程序或執行緒排程“,從CPU資源管理的角度排程執行的單位。
效能準則:
- 物件導向的效能準則1:
- 週轉時間:作業從提交到完成所經歷的時間——批處理系統
- 響應時間:使用者從輸入一個請求到系統給出首次響應的時間——分時系統
- 物件導向的效能準則2:
- 截止時間:開始截止時間和完成截止時間--實時系統,與週轉時間有些相似。
- 優先順序:可以使關鍵任務達到更好的指標
- 公平性:不因作業或程序本身排程特性而使上述指標過分惡化。
- 面向系統的排程
- 吞吐量:單位時間內完成的作業數——批處理系統。
- 處理機利用率
- 各種資源均衡利用
佔用CPU的方式:
- 不可搶佔式
- 搶佔式
執行時間 = 執行時間。週轉時間 = 執行時間+等待時間。
批處理系統的排程演算法
無需與使用者互動,也不需要很快地響應;
如編譯器、科學計算等。
- FCFS 先來先服務:有利於CPU繁忙的作業,不利於IO繁忙的作業。
- SJF 最短作業優先:提高系統的吞吐量,改善平均週轉和平均帶權週轉。
- SRTF 最短剩餘時間優先
- HRRF 最高響應比優先
- 每次選擇作業投入執行時,先計算後備作業佇列中每個作業的響應比RP,選擇最大的作業投入執行。
- \(RP = 1+\frac{作業已等待時間}{作業服務時間}\)
- 等得越久、工作時間越短,越容易被投入執行
- 非搶佔式,飢餓現象不會發生
- 但是每次計算響應比會有一定的時間開銷。
互動式系統的排程演算法
與使用者互動頻繁,長時間等待使用者輸入,響應時間要快
如WPS、GUI等。
-
時間片輪轉RR(最常用)
- 時間片過長——>退化為FCFS演算法,過短:響應時間長
- 數目越多,時間片應該越小。
- 應當使使用者輸入在一個時間片內能處理完。
-
多級佇列
-
多級反饋佇列
- 設定多個就緒佇列,分別賦予不同的優先順序,佇列1的優先順序最高。規定每個佇列優先順序越低,時間片越長。
- 新程序進入記憶體後,先投入佇列1的末尾,按FCFS演算法排程;若一個佇列1的時間片內未完成,則降低投入到佇列2的末尾,如此迴圈直到完成。
- 僅當高優先順序的佇列為空時,才排程較低優先順序的佇列中的程序執行。如果程序執行時有新程序進入較高 優先順序的佇列,則搶先執行新程序,並把被搶先的程序投入原佇列的末尾。
實時系統的排程演算法
有實時要求,不能被低優先順序程序阻塞;響應時間要短且穩定。
如影片、音訊、控制類。
實時系統是一種實踐起著主導作用的系統,當外部物理裝置想計算機發出一個訊號,要求計算機必須在確定的時間範圍內恰當地給出反應。
實時系統通常將對不同刺激的響應指派給不同的程序,且每個程序的行為是可預測的。
![image-20240603211828410](https://cdn.jsdelivr.net/gh/maotougu/picture-for-Typore/typore_img/image-20240603211828410.png)
實時排程演算法:
-
靜態表排程
透過對所有周期性任務的分析預測,事先固定一個排程方案
-
單調速率排程RMS
任務的週期越小,其優先順序越高。
任務集可排程的充分必要條件:\(\sum_{i=1}^n\frac{C_i}{T_i}≤n(\sqrt[n]{2}-1)≈0.69\)
搶佔式。
-
最早截止時間優先演算法EDF
任務絕對截止時間越早,其優先順序越高。
任務集可排程的充分必要條件:\(\sum_{i=1}^n\frac{C_i}{T_i}≤1\)
誰的DDL最急,誰先跑。
搶佔式。
-
最低鬆弛度優先演算法LLF
鬆弛度 = 任務截止時間- 本身剩餘執行時間- 當前時間
任務集可排程的充分必要條件:\(\sum_{i=1}^n\frac{C_i}{T_i}≤1\)
死鎖
- 死鎖定義:一組程序中,每個程序都無限等待組內其他程序所佔有的資源,在無外力介入的條件下,將因永遠分配不到資源而無法執行的現象。
- 資源的種類:可剝奪資源;非可剝奪資源;臨時性資源。
- 死鎖發生的四個必要條件:
- 互斥條件
- 請求和保持資源
- 不可剝奪條件
- 環路等待條件
其他一些定義:
- 活鎖:任務或執行者沒有被阻塞,由於某些條件沒有被滿足,導致一直重複嘗試。
- 與死鎖的區別:處於活鎖的實體是在不斷地改變狀態,而處於死鎖的實體表現為等待;活鎖有可能自行解開,死鎖不能。
- 避免活鎖:先來先服務策略。
- 飢餓:某些程序可能由於資源分配策略導致長時間等待。
處理死鎖的方法
- 不允許死鎖發生:預防死鎖(靜態)、避免死鎖(動態)
- 允許死鎖發生:檢測與解除死鎖;無所作為:鴕鳥演算法。
死鎖預防
- 打破互斥條件
- 打破請求且保持的條件
- 打破不可剝奪條件
- 打破迴圈等待條件
死鎖避免
不限制有關資源的申請,而是對程序鎖發出的每一個申請資源命令加以動態的檢查,根據檢查結果決定是否進行資源分配。
安全序列
定義:一個序列{P1,P2……,Pn}是安全的,是指若對於每一個程序Pi,它需要的資源可以被系統中當前可用資源加上所有所有程序Pj(j<i)當前佔有的資源之和所滿足。
銀行家演算法
判斷一次資源請求分配是否可行。
特點:允許互斥、部分分配和不可搶佔,可以提高資源利用率。
過程:
- 如果request_i<=need_i,轉向2,否則認為出錯
- 如果request_i<=Available,轉向3,否則Pi必須等待
- 系統試探分配,同時修改Available等數值
- 系統執行安全性演算法,判斷分配後是否處於安全狀態;
- 若安全則正式將資源分配給Pi
- 不安全則試探分配作廢,Pi繼續等待。
安全性演算法
判斷系統是否處於安全狀態。
過程:
分配所需——釋放全部——標記已完成
不斷迴圈,直到所有程序的Finish=true。
相當於找一個安全序列。
死鎖檢測
儲存資源的請求和分配資訊,利用某種演算法對這些資訊加以檢查,以判斷是否存在死鎖。死鎖檢測演算法主要是檢查是否有迴圈等待。
資源分配圖
用有向圖描述系統資源和程序的狀態。用圓圈代表程序,矩形代表一類資源,矩形中的小圈代表每個資源;有向邊代表資源的分配和請求。
- 存在死鎖一定存在環路:
- 但有環路不一定有死鎖:
封鎖程序:某個程序由於請求了超過系統中現有的未分配資源數目的資源,而被系統封鎖的程序
非封鎖程序:就是沒有被封鎖的程序
資源分配圖的化簡方法:
假設某個RAG中存在一個非封鎖程序Pi:
- 當Pi有請求邊時,首先將請求邊變成分配邊,一旦Pi的所有資源請求都得到滿足,就刪去這些分配邊。
死鎖定理:
系統中某個時刻t為死鎖狀態的充要條件是t時刻系統的資源分配圖是不可完全化簡的。
完全化簡:在經過一系列的簡化後,若能消去圖中的所有邊,式所有的程序都成為孤立節點,則稱該圖是可完全化簡的。
死鎖解除
- 剝奪資源:掛起/啟用一些程序,剝奪它們的資源以解除死鎖
- 撤銷程序