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