原文:http://sparkandshine.net/priority-scheduling-inversion-inheritance-ceiling-2/
本文介紹優先級調度產生的優先級反轉問題及解決反轉問題的方法,包含禁止中斷、不可搶占、優先級繼承、優先級天花板。
目錄 [hide]
1. 優先級調度和優先級反轉
高優先級優先調度。根據進程緊急程度、重要性賦予不同優先級(可以靜態,也可以動態調整),進程調度時,從就緒隊列中選取優先級最高的進程運行。看似很簡單,然而,當多個進程訪問同一個臨界資源時,可能會出現優先級反轉問題。
1.1 優先級反轉
舉個例子,系統三個進程的偽代碼如下(PV指信號量,CS指臨界區):
- P1: P; CS; V
- P2: program
- P3: P; CS; V
這三個進程到達順序為P3, P2, P1
(如箭頭所示),他們的優先級為P1>P2>P3
,如圖1所示。
假設采用搶占式優先級調度算法,可以作出進程執行順序,如下:
進程P3先到達,先運行,進程進入臨界區;此時P2到達,P2優先級高於P3,搶占P3獲得CPU執行權;P2運行一段時間,恰巧P1到達,P1優先級高於P2,搶占P2獲得CPU執行權;P2運行到臨界區,企圖進入臨界區,然而此時臨界區被P3占用,P1不得以只能進入阻塞狀態;現在CPU空閑,從[P2, P3]選取高優先級進程(即P2)運行(這里,低優先級進程P2執行,而高優先級P1只能干瞪眼,這種現象稱為優先級反轉);P2運行完,輪到P3,P3運行完,釋放臨界區,P1進入就緒態,獲得CPU執行權。
透過這個例子,我們可以發現優先級反轉出現在一個高優先級任務等待訪問一個被低優先級任務正在使用的臨界資源,此時,高優先級任務阻塞了;同時,該低優先級任務被一個次高優先級的任務所搶先(preempt),導致低優先級任務得不到執行,無法及時地釋放該臨界資源。可見,高優先級任務和次高優先級任務的優先級反轉了。
解決優先級反轉方法有多種,包括禁止中斷、禁止搶占、優先級繼承、優先級天花板等。在介紹解決方法之前,先看一個真實的例子,放松下。
1.2 一個真實的例子
火星探路者(The Mars Pathfinder)是第一個到達火星的無人飛行器(於1996年12月份離開地球,1997年3月登陸火星)。火星探路者號上運行的操作系統是VxWorks(一款嵌入式實時操作系統)。
探路者有一個消息總線(information bus),用於在不同部件之間傳遞信息,該消息總線屬於臨界資源,需要互斥訪問。
現在故事開始,
- 高優先級進程P1:消息總線進程,通過消息總線檢索數據(retrieve published data)
- 中優先級進程P2:通信進程,運行時間長
- 低優先級進程P3:氣象數據收集進程,將收集到的氣象數據放到消息總線上,運行頻率不高
試想這么一種情況,P3獲取消息總線(臨界資源)之后,被P2搶占,長進程P2被P1搶占,但P1因臨界資源被P3拿着不得以進入阻塞狀態,此時P2撿到大便宜,輪到他運行。喪心病狂的是,P2是個長進程,運行時間長。那么,P1長時間得不到運行,系統中看門狗由此判定系統出現重大錯誤(這可是實時操作系統),於是重啟系統,導致數據丟失。
更多關於火星探路者上優先級反轉有趣內容,見What really happened on Mars Rover Pathfinder。
2. 不可搶占和禁止中斷
2.1 不可搶占
若采用非搶占(non-preemptive),就不會存在優先級反轉問題。非搶占方式是指某一進程被調度運行后,除非由於它自身的原因不能運行,否則一直運行下去。
Non-preemptive multitasking is a style of computer multitasking in which the operating system never initiates a context switch from a running process to another process.
Instead, processes voluntarily yield control periodically or when idle or logically blocked in order to enable multiple applications to be run concurrently.
接上例,在不可搶占方式下,進程的執行順序如下圖所示。
P3一口氣運行完,不會被P2搶占,此時P1還沒到來,運行P2,最后才是運行P1。
盡管這是一個解決方法,但背離了優先級初衷,並不是一個好的方案。
2.2 禁止中斷
關閉中斷,進入臨界區;退出臨界區,開中斷。其實,這是一種避免臨界資源被交叉訪問的一種解決方法。延續上述的例子,使用禁止中斷方法,進程的執行順序示意圖如下:
盡管P2在P3執行臨界區到達,但因為禁止中斷,期間不會發生進程切換,直到P2退出臨界區(此時,關中斷),P2可以搶占P3;P2運行了一段時間,高優先級P1到來,搶占P2;P1開始運行,因為臨界資源可用,P1可以一口氣執行到結束。
禁止中斷類似於不可搶占方式,只是粒度不像不可搶占那么極端。但有可能存在誤殺,試想P1沒有跟P3競爭臨界區。
3. 優先級繼承
優先級繼承(priority inheritance)是指當高優先級進程(P1)請求一個已經被被低優先級(P3)占有的臨界資源時,將低優先級進程(P3)的優先級臨時提升到與高優先級進程一樣的級別,使得低優先級進程能更快地運行,從而更快地釋放臨界資源。低優先級進程離開臨界區后,其優先級恢復至原本的值。
接着上面的例子,采用優先級繼承策略,三個進程執行順序如下:
3.1 Linux
Linux實現了優先級繼承策略。
- #include <pthread.h>
- int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict attr, int *restrict protocol);
- int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
參數protocol
取值可以是(在pthread.h
定義了):
- PTHREAD_PRIO_NONE
- PTHREAD_PRIO_INHERIT
- PTHREAD_PRIO_PROTECT
詳情見:pthread_mutexattr_getprotocol(3) – Linux man page。
3.2 存在問題
相對於不可搶占和禁止中斷,優先級繼承似乎好得多,然而,優先級繼承依然有問題。
(1)潛在死鎖
以下圖為例
(2)鏈阻塞chained blocking
以下圖為例
幸運的是,接下來要介紹的優先級天花板,可以解決上述這兩個問題。
4. 基於棧的優先級天花板
下面描述的是Stack-Based Priority Ceiling Protocol 而不是 the basic priority-ceiling protocol 兩者是有區別的
優先級天花板(priority ceiling)是指將申請某資源的任務的優先級提升到可能訪問該資源的所有任務中最高優先級任務的優先級。
每個臨界資源R
賦予一個優先級天花板(priority ceiling),取所有可能訪問臨界資源R
的所有進程中優先級最高的作為R
的優先級天花板。舉例,進程[P1, P2, P3]都會訪問臨界資源R
,那么,R
的優先級天花板為1(跟最高優先級P1一樣)。
當一個進程獲取到臨界資源,就將該進程的優先級提升到優先級天花板,這樣,該進程不會被其他可能使用該臨界資源的進程搶占,從而得到更快執行,更快地釋放臨界資源。釋放臨界資源后,恢復優先級。
舉例,如下圖所示,進程[P1, P3]會訪問臨界資源S1,因此S1的優先級天花板為1;同理可得,S2的優先級天花板也為1。接下來看進程的執行順序,P3成功占有臨界資源S1,此時P3優先級被提升至1,順利執行完臨界區的代碼,恢復優先級;P2搶占P3,同理,P2優先級提升至1,P2也可以執行完臨界區的代碼;P1搶占P2,此時,臨界資源S1和S2皆已釋放,P1可以一口氣執行到底。可見,這里不存在鏈阻塞問題(chained blocking)。
優先級天花板的主要思想是認為系統中的資源都很寶貴,為了讓占有臨界資源的進程盡快釋放資源,系統將進程優先級提升到優先級天花板,讓進程不會被其他可能使用該臨界資源的進程搶占。但這樣的策略有一個隱含前提,事先知道臨界資源的優先級天花板,這在通用操作系統(比如Linux)很難做到,但在實時操作系統倒是有可能,μC/OS-II 2.52就實現了優先級天花板。
5. Random boosting
Random boosting is a strategy used by the scheduler in Microsoft Windows to avoid deadlock due to priority inversion. Ready threads holding locks are randomly boosted in priority and allowed to run long enough to exit the critical section.
6. Avoid blocking
Because priority inversion involves a low-priority task blocking a high-priority task, one way to avoid priority inversion is to avoid blocking, for example by using non-blocking synchronization or read-copy-update.
參考資料:
[1] What really happened on Mars Rover Pathfinder
[2] Priority Ceiling Protocol – GeeksforGeeks
[3] ResourceAccessProtocols.pdf