優先權反轉(priority inversion)
優先權排程承諾高優先權的執行緒會搶在低優先權者之前執行。優先權反轉,則是那種令人不安的情形:由於一把共用的鎖,一條高優先權的執行緒最後實質上排在一條低優先權者之後等待——優先權看起來顛倒了。想像一位貴賓卡在廁所排隊隊伍裡,因為唯一的隔間被一名基層員工佔著,而那名基層員工又卡住了,因為一群中階主管不斷插到他前面、永遠不讓他做完。儘管擁有最高優先權,這位貴賓卻無限期地等在大樓裡動作最慢的人後面。
用三條執行緒講清楚確切機制:H(高優先權)、M(中)、L(低)。L 取得一把鎖、進入它的臨界區間。H 醒來,嘗試取得同一把鎖,因為 L 持有它而阻塞——到此還算合理,H 必須短暫等 L。但這時 M(它不需要任何鎖)變成可執行。由於 M 的等級高於 L,排程器就改跑 M 而不是 L。L 無法前進去釋放鎖,於是 H 持續被阻塞。只要中優先權的工作不斷到來,一個接一個的 M 就先佔 L,L 永遠做不完,而 H——最重要的那條執行緒——竟被比它自己還不重要的工作給餓死。這條高優先權執行緒並非直接被同儕阻擋,而是透過「一把被某人持有、而那個人又一直被中優先權執行緒先佔」的鎖,間接地被阻擋。
這並非紙上談兵:一個著名案例幾乎毀掉 1997 年的火星拓荒者號任務,其登陸器一再重置,正是因為一個高優先權任務被一個低優先權任務反轉了。標準療法是優先權繼承:當一條低優先權執行緒持有一把「高優先權執行緒正在等」的鎖時,這條低優先權執行緒暫時繼承那個高優先權,於是中優先權的執行緒再也無法先佔它。它迅速做完臨界區間、釋放鎖,並回復到自己的優先權;H 隨即前進。(相關的方案還有優先權天花板協定,會把持有者提升到一個預先定義的天花板。)這正是真正的互斥鎖能提供、而普通號誌無法提供的那種「知道擁有者」的功能,並且在「錯過期限即為失敗」的即時系統中至關重要。
火星拓荒者號(1997):一個高優先權的資料匯流排任務阻塞在一把被低優先權氣象任務持有的互斥鎖上,而中優先權的通訊任務又不斷先佔那個氣象任務。一個看門狗計時器看到高優先權任務卡住,就一遍遍重置系統——直到工程師啟用了優先權繼承。
高優先權任務透過共用鎖排在低優先權任務之後;優先權繼承把持有者提升來打破它。
真正的禍首是「中優先權執行緒先佔鎖的持有者」,而不只是高低那一對。優先權繼承能修正它;普通號誌(沒有擁有者)無法提供它。