文獻標識碼: A
μC/OS-II是由Jean Labrosse編寫的具有高度可移植性且源碼公開的嵌入式實時操作系統(tǒng)內核,可用于8 bit、16 bit、32 bit嵌入式微處理器或DSP中。μC/OS-II可以管理64個任務,各任務有自己單獨的棧,采用基于優(yōu)先級的可搶占式PBP(Priority Based Preemptive)調度策略,絕大多數服務的執(zhí)行時間具有確定性μC/OS-II已被成功地應用于各種系統(tǒng),在眾多領域中,多種基于μC/OS-II設計的產品已經證明了μC/OS-II內核的穩(wěn)定性,其安全性和穩(wěn)定性已通過美國FAA認證。
μC/OS-II操作系統(tǒng)同時也是可剝奪型內核,以保證最重要的進程(通常是優(yōu)先級最高的進程)能夠及時得到運行。但是如果用傳統(tǒng)的信號量等機制對共享資源進行互斥操作,在某些時間里會出現(xiàn)高優(yōu)先級進程被低優(yōu)先級進程堵塞的現(xiàn)象,這種現(xiàn)象稱為優(yōu)先級反轉。本文討論優(yōu)先級反轉現(xiàn)象的原因,并給出2種抑制優(yōu)先級反轉現(xiàn)象的具體方法。
1 優(yōu)先級反轉現(xiàn)象
使用實時內核,優(yōu)先級反轉問題是實時系統(tǒng)中出現(xiàn)最多的問題。優(yōu)先級反轉發(fā)生在一個高優(yōu)先級的任務被迫等待一段不確定時間的過程中[1]。優(yōu)先級反轉現(xiàn)象示意圖如圖1。
圖1中,空白框為任務正常運行過程;陰影框為任務取得信號量后的運行過程。在圖中3個任務優(yōu)先級的高低為T1>T2>T3,T1和T3在運行過程中都需要使用同一資源,T2不需要使用該資源。當T3先占用該資源,T1任務需要等待,直到T3任務釋放占用的共享資源。由于T2的優(yōu)先級比T3高,所以剝奪了T3的CPU使用權,使得T3釋放信號量的時間向后拖延,所以T1的運行情況更加惡化,T1取得信號量的時間隨之推遲。這樣,原本優(yōu)先級最高的T1任務,在經過以上過程后,優(yōu)先級反而降到了最低。這時,系統(tǒng)中就發(fā)生了優(yōu)先級反轉的現(xiàn)象。
優(yōu)先級反轉原因可歸納為:高優(yōu)先級的任務由于要等待被低優(yōu)先級任務占有的臨界資源而被中優(yōu)先級任務阻塞,而此時具有中優(yōu)先級的任務搶占了低優(yōu)先級任務的CPU時間,導致具有中優(yōu)先級的任務先于高優(yōu)先級任務而執(zhí)行。
2 優(yōu)先級反轉的解決方案
優(yōu)先級反轉問題的解決辦法有優(yōu)先級置頂和優(yōu)先級繼承2種[2]。
采用優(yōu)先級置頂的方案,首先在創(chuàng)建互斥信號量時就應同時設置一個相應的置頂優(yōu)先級,當首先申請到該資源的任務a未釋放而又有一個更高優(yōu)先級的任務b試圖申請時,內核會將任務a的優(yōu)先級提升到置頂優(yōu)先級,該置頂優(yōu)先級高于任何可能申請該資源任務的高優(yōu)先級。優(yōu)先級置頂的意義在于使占有資源的低優(yōu)先級任務盡快完成,讓高優(yōu)先級任務的等待不至過長。
而優(yōu)先級繼承的思想是:在出現(xiàn)上述情況時,提高低優(yōu)先級任務的優(yōu)先級使其與高優(yōu)先級任務的優(yōu)先級等同。而μC/OS-II卻不支持這種方法[3],需要通過修改μC/OS-II內核來實現(xiàn)優(yōu)先級繼承。
2.1 優(yōu)先級置頂方案
要在μC/OS-II實現(xiàn)優(yōu)先級置頂[4],需要用到互斥信號量(Mutex)。
互斥型信號量的創(chuàng)建是由函數OSMutexCreate( )完成的,它首先檢查PCP的優(yōu)先級數值是否己經被其他任務使用,如果還沒有使用就占用這個優(yōu)先級。然后得到一個新的事件控制塊ECB,OSMutexCreate( )置mutex的值為有效,同時將PCP保存起來。
OSMutexPend( )函數在獲取互斥信號量Mutex時,如果Mutex可用,并且占有信號量任務的優(yōu)先級不是最高,則提升此任務的優(yōu)先級置PIP,即置頂優(yōu)先級,使它盡快執(zhí)行并退出臨界區(qū)從而釋放Mutex。釋放信號量函數OSMutexPost( )則是將當前任務的優(yōu)先級恢復原值,并檢查是否有任務仍在申請該資源。
利用優(yōu)先級置頂解決前面提到的優(yōu)先級反轉的過程如圖2所示。
以開始系統(tǒng)初始化,直到T1任務開始請求信號量的時刻,系統(tǒng)運行情況和應用普通信號量時的情況是一致的。t2時刻,T1任務開始啟動,請求信號量,此時系統(tǒng)得知T1任務所需的信號量正在被T3任務所占據,故提高T3任務的優(yōu)先級,使之高于請求該信號量的所有任務的優(yōu)先級;t3時刻,T1任務由于得不到信號量而被掛起,此時由于T3任務的優(yōu)先級高于T1和T2任務,所以系統(tǒng)讓T3任務先完成,從而釋放信號量。當T3任務釋放信號量的時候,系統(tǒng)得知T3任務的優(yōu)先級是被暫時提高的,所以恢復T3任務的優(yōu)先級,此時T1任務可以請求并得到信號量;t4時刻,T1任務由于得到信號量而開始運行;t5時刻,T1任務運行完畢,由系統(tǒng)切換任務,使T2任務開始運行。在一定程度上抑制了優(yōu)先級反轉。在μC/OS-II系統(tǒng)中建立如上所述的3個任務,作用時分別輸出格式為“自己的任務名稱is running”的字符串。使用了互斥信號量后的實驗結果如圖3所示。
2.2 優(yōu)先級繼承方案
在μC/OS-II中,由于不同的任務不能對應同一個優(yōu)先級,所以不支持上述方法。不過,可以通過修改操作系統(tǒng)的內核,使之成為可能,從而用優(yōu)先級繼承的方案解決優(yōu)先級反轉現(xiàn)象。這里采用類似于時間片輪番調度法的方案,在同一優(yōu)先級上對不同任務進行調度。
這種方法給處于同一優(yōu)先級的不同任務都分配一個時間片,當內核運行到某一任務時,對同優(yōu)先級且處于就緒態(tài)的任務依次進行調度,即當就緒態(tài)中先到的任務用完自己的時間片后,CPU控制權轉讓給就緒態(tài)中后一任務。該任務用完自己的時間片后,CPU控制權又轉讓給后一個就緒態(tài)任務。當就緒態(tài)的每一個任務都被調度一次之后將重新為它們分配時間片,然后又開始新周期的調度。在調度過程中如果有一個比當前任務優(yōu)先級更高的任務由其他態(tài)變成了就緒態(tài)(被創(chuàng)建或獲取了一個信號量等等),當前任務的CPU控制權將被剝奪;空閑任務仍然是等到其他任務都退出就緒態(tài)才獲得CPU使用權。
這種方法的優(yōu)點不僅體現(xiàn)在可以讓同一優(yōu)先級對應不同的任務,從而進行優(yōu)先級繼承,還體現(xiàn)在可以增加操作系統(tǒng)調度任務的最大數目,這使應用系統(tǒng)的開發(fā)更加靈活。因為在不允許一個優(yōu)先級對應不同任務的μC/OS-II中,用戶能夠自己創(chuàng)建的任務數目最多為56個。
在μC/OS-II中,實現(xiàn)優(yōu)先級繼承方案應該首先在任務控制塊(TCB)的結構體中添加構成雙向鏈表的前驅節(jié)點指針(變量名為OSMYnext)、后繼結點指針(變量名為OSMYprev)和2個用于指示時間的變量(OSMYtime和OSMYtimeremain)。指針的作用是用來查找同一優(yōu)先級的不同任務,便于添加新任務和刪除已經釋放了信號量的任務。在沒有其他任務和自己處于同一優(yōu)先級的狀態(tài)下,鏈表的前后指針均指向自己。變量OSMYtime的作用表示分給該任務的時間片長度,OSMYtimeremain表示當前時間片剩余時間。
由于當前任務的時間片使用完時,就會被從就緒表OSRdyGrp以及OSRdyTbl[ ]中清除,這樣,正常的調度將被打亂,所以還需增加保存臨時OSRdyGrp和OSRdyTbl[ ]的變量OSTempGrp和OSTempTbl[ ]。由于在創(chuàng)建任務時μC/OS-II會比較該任務和已建立的任務的優(yōu)先級是否相同,所以還需把任務創(chuàng)建函數中相應代碼進行屏蔽。
時鐘節(jié)拍函數OSTimeTick( )在時間片調度過程中起到了修改時間片計數器的作用,每一次時鐘節(jié)拍的到來都會引起時間片的減少。在OSTimeTick( )函數中,主要完成以下工作:首先檢查同優(yōu)先級的雙向鏈表指針是否指向自己。如果指向自己,則說明在這一優(yōu)先級上,只有自己一個任務。如果指向其他的任務,則要通過遞減正在運行的任務的時間片來確定分給該任務的時間片是否用完。
如果時間片沒有用完,則執(zhí)行OS_Sched()函數,讓內核進行調度;如果時間片已經用完,則讓時間片重新賦值,然后同樣進行調度,在沒有更高優(yōu)先級的任務處于就緒態(tài)時,系統(tǒng)將運行鏈表所指示的下一個任務。其主要步驟的流程圖如圖4所示。
經過以上步驟,就可以在μC/OS-II系統(tǒng)中基本實現(xiàn)時間片輪番調度,不過要想解決優(yōu)先級反轉的問題,還需要做以下工作。
當一個任務進入等待互斥信號量OSMutexPend( )函數時,首先判斷當前任務的優(yōu)先級是否高于已經得到并且還沒釋放該資源的任務優(yōu)先級。如果當前的任務優(yōu)先級高,則要將得到該資源的任務優(yōu)先級提到當前任務的優(yōu)先級水平,并且把當前任務加到自己的雙向鏈表中,再執(zhí)行一次內核調度。
當任務執(zhí)行OSMutexPost( )釋放互斥信號量時,如果在其擁有信號量的過程中被提升過優(yōu)先級,則將恢復之前的優(yōu)先級。然后查看是否還有任務在等待該信號量,準備下一次調度。
用優(yōu)先級繼承的方法測試,同樣選取T1、T2、T3 3個任務,進行同優(yōu)先級置頂方案相同的實驗,得到如圖5所示的結果。
從圖5可以看出,用時間片解決優(yōu)先級反轉的效果與優(yōu)先級置頂大致相同,區(qū)別僅在于當T3任務取得資源運行時,時間片用完后,T1任務又開始申請該資源,而T3并未放棄,所以出現(xiàn)如圖5的結果。如果T3的時間片設置過小,這一過程就將頻繁發(fā)生,從而降低了效率。所以如果系統(tǒng)當前的任務集合相對簡單,則在發(fā)生優(yōu)先級反轉時,把低優(yōu)先級任務的時間片調大一些為好。
運用時間片輪番調度法,解決了在μC/OS-II系統(tǒng)中實現(xiàn)優(yōu)先級繼承的方案,在一定程度上抑制了優(yōu)先級反轉現(xiàn)象,提高了系統(tǒng)的實時性,還增加了系統(tǒng)同時運行任務的最大數目,提高了系統(tǒng)的運行效率。
優(yōu)先級反轉是任何一個多任務實時操作系統(tǒng)都無法避免的問題。本文分析了該現(xiàn)象產生的原因,主要討論了μC/OS-II中運用mutex和時間片輪番調度解決該問題的方法并對其可行性進行了驗證。相對優(yōu)先級繼承和優(yōu)先級置頂策略,在可能出現(xiàn)優(yōu)先級反轉的情況下,動態(tài)地改變任務優(yōu)先級能夠保證高優(yōu)先級任務的執(zhí)行,有效提高了系統(tǒng)的實時性。
參考文獻
[1] 楊宗德,張兵μC/OS-II標準教程[M].北京:人民郵電出版社,2009:153-156.
[2] LABROSSE J.μC/OS-II the real-time kernel[M].Lawrence,R&D Books,2003:47-64.
[3] LABROSSE J J.嵌入式實時操作系統(tǒng)μC/OS-II(第2版) [M].北京:北京航空航天大學出版社,2003:44-46.
[4] 任哲.嵌入式實時操作系統(tǒng)μC/OS-II原理及應用[M].北京:北京航空航天大學出版社,2005:124-130