王浩波,王宜懷,劉長勇,劉中華
(1.蘇州大學(xué) 計算機(jī)科學(xué)與技術(shù)學(xué)院,江蘇 蘇州 215006; 2.武夷學(xué)院 數(shù)學(xué)與計算機(jī)學(xué)院,福建 武夷山 354300)
實時操作系統(tǒng)RTOS[1](real time operation system)是一種具備較高實時性及穩(wěn)定性的嵌入式系統(tǒng)。一個復(fù)雜的嵌入式系統(tǒng)整體功能可以在RTOS的支持下,通過任務(wù)間通信的方式保證各個任務(wù)間能協(xié)調(diào)有序、互不沖突地同步運(yùn)行。線程信號作為RTOS的同步與通信方式中最基本的一種,用來通知線程發(fā)生了異步事件,進(jìn)而實現(xiàn)線程間消息傳遞。截至目前,也有少數(shù)學(xué)者在線程信號響應(yīng)機(jī)制原理方面展開研究。例如,uClinux實時操作系統(tǒng)是通過信號屏蔽字的方式實現(xiàn)任務(wù)間協(xié)同管理與控制[2]。而Vxworks的任務(wù)間同步與通信是在軟件信號[3]設(shè)立的基礎(chǔ)上完成。eCOS則是利用條件變量來完成任務(wù)間的通信[4]。
但是,這些研究僅針對線程信號的調(diào)用算法或應(yīng)用展開研究,而對RTOS內(nèi)部的線程信號響應(yīng)原理、響應(yīng)時間性能或運(yùn)行流程并未介紹,不足以讓讀者深刻理解同步與通信原理機(jī)制。為此,通過對RTOS的線程信號通信原理、響應(yīng)流程以及其它關(guān)鍵技術(shù)要點的分析,在此基礎(chǔ)上提出基于printf方法輸出線程信號響應(yīng)機(jī)制流程的剖析方法,以STM32L431芯片為例,在mbedOS測試工程中不僅給出了printf輸出語句的加入位置及方法,同時也對線程信號內(nèi)部響應(yīng)機(jī)制流程及時間進(jìn)行了系統(tǒng)分析[5]。結(jié)果分析表明,將線程信號內(nèi)部整個響應(yīng)機(jī)制流程信息通過printf方法輸出顯示在PC機(jī)中,不僅有助于讀者從更加微觀的層面來理解同步與通信原理機(jī)制,也為深入理解或設(shè)計新的RTOS提供了重要的理論研究基礎(chǔ)。
在RTOS的同步與通信機(jī)制中,相比于通過事件字來表達(dá)多種可能的邏輯結(jié)果,線程信號是最簡單的同步手段,常應(yīng)用于協(xié)調(diào)任務(wù)間或中斷與任務(wù)間的通信、僅表達(dá)某一具體的情況而無需傳遞數(shù)據(jù)的場景。
線程信號作為線程間通信的重要媒介之一,用來通知線程發(fā)生了異步事件,操作系統(tǒng)內(nèi)核也可以因為內(nèi)部事件而給線程發(fā)送信號,通知線程發(fā)生了某個事件,在mbedOS中采用線程信號、eCOS中采用條件變量、uClinux中采用信號屏蔽字、Vxworks中采用軟件信號的方式來實現(xiàn)。
若兩個任務(wù)間的同步與通信是通過線程信號的方式來實現(xiàn),則其中必定會有一個任務(wù)通過某種方式在等待該線程信號,同時另外一個任務(wù)則采用某種方式或函數(shù)設(shè)置具體的線程信號值,例如在mbedOS中,線程調(diào)用signal_wait函數(shù)等待一個線程信號,實際上是將所要等待的線程信號值記錄在線程控制塊的waitFlags變量中;在uClinux實時操作系統(tǒng)中,等待信號的產(chǎn)生由sigwait函數(shù)完成;Vxworks則是在程序執(zhí)行到sig_suspend這一函數(shù)處,系統(tǒng)掛起當(dāng)前任務(wù)并等待具體的軟件信號值;而eCOS在等待條件變量前會先調(diào)用cyg_cond_wait這一函數(shù)。這個時候任務(wù)狀態(tài)由就緒態(tài)切換為阻塞態(tài),并從就緒隊列移出再放到等待隊列中。之后會在另一任務(wù)設(shè)置線程信號值,如mbedOS通過調(diào)用線程設(shè)置函數(shù)signal_set設(shè)置線程信號值,實際是將要設(shè)置的具體線程信號值記錄在線程控制塊的threadFlags變量中;uClinux向特定的任務(wù)發(fā)送信號前會先調(diào)用signal函數(shù);Vxworks在kill函數(shù)的作用下,向特定的任務(wù)發(fā)送具體的信號值;而eCOS喚醒所有等待條件變量前,會事先調(diào)用cyg_cond_broadcast或cyg_cond_signal函數(shù),可分別喚醒多個或一個等待該條件變量的線程。之后它們會在各自的線程信號設(shè)置處判斷其中是否有等待具體信號值的任務(wù)或線程,若有則將其狀態(tài)由阻塞態(tài)切換為就緒態(tài),并從等待隊列移出再放到就緒隊列中。4種操作系統(tǒng)的線程信號調(diào)度對比過程如圖1所示。
圖1 4種操作系統(tǒng)的線程信號調(diào)度對比過程
在線程信號響應(yīng)機(jī)制的過程中,會涉及到線程信號的等待、線程信號的產(chǎn)生、線程信號的存儲、線程信號的識別、線程信號的響應(yīng)以及線程信號的調(diào)度等關(guān)鍵技術(shù)要點。
(1)線程信號的等待:其定義請參見文獻(xiàn)[6];
(2)線程信號的產(chǎn)生:即指明線程信號由誰負(fù)責(zé)設(shè)置,在什么時間以及什么位置被設(shè)置,設(shè)置的線程信號值是多少;
(3)線程信號的存儲:即線程信號被設(shè)置完成后,指明線程信號值存儲的時間和存儲位置;
(4)線程信號的識別:線程信號被存儲后,指明線程信號被識別的時間和識別對象;
(5)線程信號的響應(yīng):其定義請參見文獻(xiàn)[6];
(6)線程信號的調(diào)度:其定義請參見文獻(xiàn)[6]。
若任務(wù)間的同步與通信機(jī)制是通過線程信號的方式來實現(xiàn),則其內(nèi)部等待和設(shè)置線程信號的過程通常是隱藏在內(nèi)核程序中,通過printf措施將線程信號內(nèi)部響應(yīng)的中間流程信息直觀地顯示在PC機(jī)中并加以剖析,可以幫助讀者捋清線程信號響應(yīng)的整個脈絡(luò)結(jié)構(gòu),加深對該同步與通信方式的理解。
要理解線程信號響應(yīng)機(jī)制的過程,可以通過以下3種方法。第一種是直接查看源程序的方法,直接根據(jù)程序代碼含義來分析整個程序的執(zhí)行流程,該方法對于無操作系統(tǒng)程序或單一程序的分析是可行的[6]。但對RTOS而言,程序的執(zhí)行是非靜態(tài)且并非一次性運(yùn)行完成,而是由RTOS根據(jù)調(diào)度策略(mbedOS中采用優(yōu)先級搶占以及時間片輪詢調(diào)度策略)對任務(wù)進(jìn)行動態(tài)調(diào)度。因此,直接分析源程序這種靜態(tài)的方式很難模擬出RTOS輪詢調(diào)度的動態(tài)過程[7]。第二種是通過斷點調(diào)試手段,即在需要調(diào)試的語句上進(jìn)行斷點設(shè)置,通過單步跟蹤的方式逐語句分析線程信號響應(yīng)流程。但在有RTOS的情況下,其內(nèi)部會存在一個定時器中斷,該中斷會在每個時間嘀嗒到來時自動運(yùn)行,若采取斷點調(diào)試的措施,則無法進(jìn)入到定時器中斷內(nèi)部進(jìn)行語句分析,也就無法分析線程信號的響應(yīng)機(jī)制。還有一種是printf輸出方法,printf調(diào)試方法[8]作為動態(tài)分析的最原始形式之一,被廣泛應(yīng)用在各個領(lǐng)域中。例如:在CPU仿真技術(shù)中通過printf方法可以打印輸出調(diào)試信息;在計算機(jī)視覺應(yīng)用中通過printf調(diào)試方法將中間過程信息打印輸出;還可以在程序功能分析過程中采用printf調(diào)試方法輸出程序錯誤信息。因此,借鑒類PC機(jī)的printf調(diào)試方法,不但能夠?qū)崿F(xiàn)將線程信號響應(yīng)過程的各種狀態(tài)動態(tài)地輸出顯示在PC機(jī)中,也有助于更好地剖析線程信號響應(yīng)機(jī)制的內(nèi)部過程。
為更好地剖析線程信號響應(yīng)機(jī)制過程,可以考慮從以下兩個方面插入相應(yīng)的printf語句輸出過程信息以及響應(yīng)時間。
線程信號整個響應(yīng)流程信息輸出注重的是任務(wù)狀態(tài)的變化、任務(wù)處于哪個隊列、任務(wù)是怎樣進(jìn)出隊列的、等待的線程信號是否發(fā)生改變以及在哪里被設(shè)置。因此,printf語句應(yīng)該插入在調(diào)用線程信號等待、設(shè)置以及任務(wù)進(jìn)出各種列表函數(shù)的前后等位置,這樣可以輸出各種狀態(tài)信息。
在剖析RTOS線程信號機(jī)制的響應(yīng)時間時,應(yīng)著重考慮線程信號響應(yīng)的快慢和耗費(fèi)的時間長短。在這一過程中,printf語句的執(zhí)行也需花費(fèi)一定的執(zhí)行時間:由于主控芯片STM32L431采用的是48 MHz的內(nèi)核時鐘頻率,故通過printf調(diào)試手段打印輸出一個字符約需77 μs,由此可算出所有printf執(zhí)行的時間。按照無損檢測[9]的要求規(guī)定:待檢測對象性能的完整性不可以受到所選用的檢驗技術(shù)及檢測設(shè)備的干擾。因此,此處可以通過代碼插樁的方法來測試響應(yīng)時間性能,即采用變量記錄響應(yīng)時間并在任務(wù)獲得響應(yīng)時才利用printf方式輸出顯示時間信息,而不是在源程序中所有位置都插入printf語句,通過這種方式才可以比較準(zhǔn)確地計算出線程信號響應(yīng)整個過程的時間。將任務(wù)執(zhí)行到線程信號等待語句signal_wait處的時刻設(shè)置為T0, 標(biāo)志線程信號等待開始。將任務(wù)執(zhí)行到線程信號值設(shè)置語句signal_set處的時刻設(shè)置為T1, 標(biāo)志線程信號的產(chǎn)生。將任務(wù)執(zhí)行到線程信號存儲語句處的時刻設(shè)置為T2, 標(biāo)志該線程信號進(jìn)入存儲待識別階段。將任務(wù)執(zhí)行到線程信號被識別語句處的時刻設(shè)置為T3, 標(biāo)志該線程信號進(jìn)入到被識別階段。將任務(wù)執(zhí)行到線程信號由被識別到進(jìn)入就緒隊列語句處的時刻設(shè)置為T4。 最后將任務(wù)執(zhí)行到由就緒隊列取出到被RTOS調(diào)度語句處的時刻設(shè)置為T5。 完成上述時間刻度設(shè)置之后,便可以計算出線程信號在各個周期的時間差值:線程信號由產(chǎn)生到存儲為 (T2-T1)、 由存儲到被識別為 (T3-T2)、 由識別再到響應(yīng)為 (T4-T3) 以及由等待線程信號到再次被mbedOS[10]調(diào)度執(zhí)行的時間間隔為 (T5-T0)。
mbedOS是ARM公司在2014年推出的一款免費(fèi)的、跨平臺的、專為物聯(lián)網(wǎng)(IoT)中的“事物”而設(shè)計的輕量級開源嵌入式操作系統(tǒng),不僅具備一般RTOS的基本功能,開發(fā)設(shè)計人員還可以在低成本開發(fā)板上快速構(gòu)建IoT應(yīng)用原型[11],被廣泛應(yīng)用在物聯(lián)網(wǎng)設(shè)備平臺[12]以及通信與安全訪問服務(wù)機(jī)制[13]等領(lǐng)域。下面將通過實踐分析mbedOS的線程信號響應(yīng)機(jī)制。
對線程信號響應(yīng)機(jī)制的分析,主要在于要選擇好printf語句的插入位置,這樣才能輸出響應(yīng)過程的關(guān)鍵信息。
(1)在線程信號等待語句“Thread::signal_wait(GREEN_SIGNAL)”前后位置加入相應(yīng)的printf語句,用來顯示線程在等待線程信號前和獲得線程信號后的關(guān)鍵信息,在該語句之后用T5記錄線程被調(diào)度的時刻;在線程信號設(shè)置語句“thd_greenlight.signal_set(GREEN_SIGNAL)”的前后位置加入相應(yīng)的printf輸出信息,則可以顯示設(shè)置線程信號值前后的狀態(tài)變化信息,并在該語句之前用T1記錄線程信號產(chǎn)生的時刻。
(2)在“thread->waitFlags=flag”前后位置加入相應(yīng)的printf語句,用來輸出當(dāng)前線程信號等待標(biāo)志waitFlags值的變化情況,并在“osRtxThreadDelayInsert(thread, timeout)”語句之前用T0記錄線程開始等待線程信號時刻;然后在“threadFlags = threadFlagSet(thread,flag)”這一語句后面加入對應(yīng)的printf輸出語句,并用T2記錄線程信號存儲的時刻。
(3)在延時等待隊列移除線程函數(shù)osRtxThreadDelayRemove之前可用T3記錄識別到等待線程信號的具體線程的時刻;在線程進(jìn)隊函數(shù)osRtxThreadReadyPut之后可用T4記錄將等待線程信號的線程放入到就緒隊列的時刻。
(4)除此之外,還可以在線程移出函數(shù)osRtxThreadWaitExit、線程延時等待函數(shù)osRtxThreadWaitEnter等前后位置加入對應(yīng)的printf輸出信息,不僅可以直觀地跟蹤程序運(yùn)行狀態(tài),還可以顯示線程進(jìn)出各種隊列的變化情況。
mbedOS作為一款廣泛應(yīng)用于物聯(lián)網(wǎng)平臺的實時操作系統(tǒng),其內(nèi)部通過兩種機(jī)制來設(shè)置線程信號:第一種機(jī)制是在某個線程中等待線程信號,在另一線程中通過觸發(fā)SVC中斷來設(shè)置線程信號;第二種機(jī)制是在某個線程中等待線程信號,而設(shè)置具體的線程信號值則是通過PendSV中斷機(jī)制來實現(xiàn)。為準(zhǔn)確測試出線程信號的響應(yīng)時間,可以在mbedOS測試樣例工程中只設(shè)定包含兩個優(yōu)先級相同的線程,即藍(lán)燈線程和綠燈線程,并運(yùn)行在STM32L431微控制器上。mbedOS內(nèi)部的定時器中斷SysTick是通過時間嘀嗒的方式來產(chǎn)生中斷,即每個時間嘀嗒(1 ms)可以產(chǎn)生一次中斷,對應(yīng)SysTick中的計數(shù)器需要計數(shù)48 000次(STM32L431芯片內(nèi)核時鐘頻率是48 MHz,計數(shù)器采用減1的方式進(jìn)行計數(shù));而在線程的優(yōu)先級相同的情況下,mbedOS是利用時間片輪詢調(diào)度策略來選擇某個線程進(jìn)行調(diào)度,即每個時間片大小為5個時間嘀嗒。實時性能的軟件測試[14]作為一個設(shè)計和考核實時操作系統(tǒng)性能的重要方法之一,主要是通過系統(tǒng)調(diào)用的方式來獲得操作系統(tǒng)內(nèi)核中任意兩處代碼執(zhí)行的時間間隔。本文采用SVC中斷的方式來分析線程信號的響應(yīng)時間,主要有:線程信號由產(chǎn)生到存儲 (T2-T1)、 由存儲到被識別 (T3-T2)、 由識別再到響應(yīng) (T4-T3) 以及由等待線程信號到再次被mbedOS調(diào)度執(zhí)行的時間間隔 (T5-T0)。 測試方法是在時間嘀嗒中斷服務(wù)例程SysTick_Handler函數(shù)中將全局變量TimerCount(用來記錄SysTick中斷次數(shù))加1,即先取得TimerCount變量存放的絕對地址,然后給該地址存放的內(nèi)容執(zhí)行加1操作再重新賦值給該地址,通過比較不同時刻的Systick中斷計數(shù)值VAL以及中斷次數(shù)SUM(由TimerCount變量值的大小決定),采用Δt公式計算求得實際執(zhí)行時間,即線程信號在某個執(zhí)行過程需耗費(fèi)實際時間的計算公式為: Δt=Tend-Tbegin=((VALbegin-VALend)+48000*(SUMend-SUMbegin))/48(μs)。 表1給出了基于SVC中斷的線程信號響應(yīng)時間分析情況,其中 (T2-T1)、 (T3-T2)、 (T4-T3) 的響應(yīng)時間都較短,在8 μs之內(nèi),說明線程信號作為同步與通信手段能滿足實時性的要求。而綠燈線程由等待線程信號到再次被調(diào)度執(zhí)行的時間都在5 ms~6 ms之內(nèi),則可以說明在線程優(yōu)先級相同的情況下,mbedOS實時操作系統(tǒng)是采用時間片輪詢的方式來對線程進(jìn)行調(diào)度,響應(yīng)時間同樣也比較快,實時性要求能得到滿足。
表1 基于SVC中斷的線程信號響應(yīng)時間分析
基于篇幅的有限性,這里僅給出測試線程信號由產(chǎn)生到存儲 (T2-T1) 過程中的關(guān)鍵代碼,其余各時間段的測試流程分析與此類似。
(1)在時間嘀嗒中斷服務(wù)例程處理函數(shù)SysTick_Handler中設(shè)置SysTick中斷次數(shù)累加的關(guān)鍵代碼如下:
SysTick_Handler:
//棧指針(MSP或PSP)和LR(EXC_RETURN)入棧
PUSH {R0,LR}
ldr r2,=0x20001884
ldr r3,[r2]
adds r3,r3,#1
str r3,[r2]
//調(diào)用SysTick中斷服務(wù)例程osRtxTick_Handler
BL osRtxTick_Handler
//R0←堆棧中保存的R0;
//LR←堆棧中保存的LR(EXC_RETURN)
POP {R0,LR}
代碼段分析:其中0x20001884是全局變量TimerCount(用來記錄SysTick中斷次數(shù))編譯后的地址,可通過編譯后生成的Debug目錄文件下的.map文件找到該地址,先將該地址存放的數(shù)據(jù)賦值給寄存器r3,再將自加1后的數(shù)據(jù)存放回原地址即可實現(xiàn)每次觸發(fā)SysTick中斷時次數(shù)累加1。
(2)在藍(lán)燈線程調(diào)用signal_set函數(shù)之前記為T1時刻的關(guān)鍵代碼:
//T1時刻
n0=TimerCount;
v0=SysTick->VAL;
//設(shè)置綠燈信號
thd_greenlight.signal_set(GREEN_SIGNAL);
代碼段分析:n0用來記錄T1時刻觸發(fā)的SysTick中斷次數(shù);v0則記錄T1時刻Systick的計數(shù)值VAL, GREEN_SIGNAL是綠燈等待的線程信號值,大小為0x47。這個值的大小可以在宏定義處自己設(shè)定。
(3)在SVC實際處理線程信號設(shè)置函數(shù)svcRtxThreadFlagSet中,線程信號值被賦值給threadFlags變量之后記為T2時刻的關(guān)鍵代碼:
//(2)設(shè)置線程信號值
threadFlags = ThreadFlagSet(thread, flag);
//T2時刻
n5=TimerCount;
v5=SysTick->VAL;
if(v5>v0)
printf("%d ",v0-v5+(n5-n0)*48000);
else
printf("%d ",v0-v5);
代碼段分析:調(diào)用ThreadFlagSet函數(shù)將對應(yīng)線程(綠燈線程)的線程信號值設(shè)置為0x47,并存儲在threadFlags變量中,n5用來記錄T2時刻觸發(fā)的SysTick中斷次數(shù);v5則記錄T2時刻Systick的計數(shù)值VAL。
mbedOS線程信號響應(yīng)機(jī)制的測試樣例程序是基于Cortex-M4F內(nèi)核的STM32L431微控制器和STM32CubeIDE 1.0.0集成開發(fā)環(huán)境進(jìn)行的。STM32L431采用的是256 KB的片內(nèi)Flash和64 KB的靜態(tài)隨機(jī)存儲器SRAM,F(xiàn)lash主要用于程序代碼及中斷向量表的存儲,而片內(nèi)RAM主要用于各類變量的存儲[15]等。芯片采用LQFP-64封裝,不僅具有豐富的功能模塊:包括GPIO引腳、ADC模塊、PWM定時器等,還包含具備強(qiáng)大運(yùn)算能力的浮點運(yùn)算單元FPU。STM32L431微控制器不僅包括ARM Cortex-M4F內(nèi)核以及各種外設(shè)、存儲器模塊,還包含了高性能系統(tǒng)和外設(shè)兩種總線。另外,STM32L431微控制器還提供可擴(kuò)展總線用來連接其它外圍設(shè)備,其結(jié)構(gòu)如圖2所示。
圖2 STM32L431微控制器結(jié)構(gòu)
本文用到的測試工程的功能主要是在mbedOS啟動后通過主線程來創(chuàng)建3個相同優(yōu)先級的用戶線程,分別是藍(lán)燈線程、綠燈線程以及紅燈線程。然后在綠燈線程中調(diào)用signal_wait函數(shù)等待綠燈線程信號(GREEN_SIGNAL),從而實現(xiàn)綠燈的亮暗切換;而藍(lán)燈線程則是通過調(diào)用signal_wait函數(shù)來等待藍(lán)燈線程信號(BLUE_SIGNAL),進(jìn)而實現(xiàn)藍(lán)燈的亮暗切換;在紅燈線程中通過調(diào)用signal_set函數(shù)分別設(shè)置綠燈線程和藍(lán)燈線程的線程等待信號。圖3給出了mbedOS測試樣例程序的執(zhí)行流程。
圖3 mbedOS測試樣例程序的執(zhí)行流程
在測試程序中,當(dāng)程序執(zhí)行到“Thread::signal_wait(GREEN_SIGNAL)”語句時,則表示此時綠燈線程需要等待綠燈線程信號(GREEN_SIGNAL),綠燈線程阻塞被放入到等待隊列中。當(dāng)測試程序執(zhí)行到“thd_greenlight.signal_set(GREEN_SIGNAL)”語句時,則相當(dāng)于此時向綠燈線程發(fā)送了一個線程信號,綠燈線程收到該信號后,會將之前阻塞的綠燈線程從等待隊列移出并放入到就緒隊列中,由mbedOS通過時間片輪詢的調(diào)度策略,將線程狀態(tài)由阻塞態(tài)更改為激活態(tài),并進(jìn)行上下文切換,然后執(zhí)行后續(xù)的語句,即執(zhí)行g(shù)pio_reverse(LIGHT_GREEN)語句實現(xiàn)切換綠燈亮暗。藍(lán)燈線程的運(yùn)行流程與綠燈線程一樣。
在STM32L431微控制器的基礎(chǔ)上,以測量有關(guān)的確定性時序分析[16]方法為例。即在mbedOS測試工程中的對應(yīng)語句前后位置插入printf來輸出信息,圖4給出了基于線程信號工作原理的線程調(diào)度過程時序圖。
結(jié)合前面內(nèi)容分析,可以將線程信號響應(yīng)的流程分析大致分為以下9個步驟,基于篇幅局限性的原因,本文僅給出與綠燈線程相關(guān)的printf輸出信息。其中,藍(lán)燈線程的地址是20001774,綠燈線程的地址是20001834,紅燈線程的地址是200016B4,定時器線程的地址是2000136C,空閑線程地址是20001328,缺省處理函數(shù)DefaultISR的地址是8001A21。而地址200001E4表示等待隊列,地址200001D0表示就緒隊列。
(1)啟動線程
從芯片上電到操作系統(tǒng)的啟動,其中包括上電復(fù)位及mbedOS啟動兩大部分,在mbedOS啟動后,測試程序會先執(zhí)行對應(yīng)的主線程函數(shù)app_init,由該函數(shù)依次創(chuàng)建紅燈、綠燈和藍(lán)燈3個用戶線程,接著啟動這3個用戶線程,然后主線程被阻塞[17]。此時,CPU的控制權(quán)交由mbedOS內(nèi)核,開始對用戶線程的調(diào)度,即取出并激活就緒隊列中優(yōu)先級最高的紅燈線程運(yùn)行。
(2)綠燈線程等待綠燈信號
mbedOS內(nèi)部的SysTick中斷會每隔1 ms中斷一次并按照每個時間片(5 ms)為周期的方式對線程進(jìn)行輪詢調(diào)度,此時綠燈線程被激活,并通過執(zhí)行“Thread::signal_wait(GREEN_SIGNAL)”語句來等待綠燈信號GREEN_SIGNAL(0x47),在執(zhí)行該語句的過程中,由于綠燈信號此時還未產(chǎn)生,綠燈線程狀態(tài)會從激活態(tài)轉(zhuǎn)換成為阻塞態(tài),并移入等待隊列中,同時,從就緒隊列中取出優(yōu)先級最高的紅燈線程激活運(yùn)行。
printf輸出結(jié)果如下:
2.當(dāng)前運(yùn)行的線程=20001834(綠燈)開始。
2-1.當(dāng)前運(yùn)行的線程=20001834(綠燈)調(diào)用signal_wait(GREEN_SIGNAL)等待線程信號0x47。
2-1-1.設(shè)置前當(dāng)前運(yùn)行線程=20001834的等待標(biāo)識=0
5-1.調(diào)用osRtxThreadWaitEnter前等待隊列=200001E4中的線程: 2000136C->0->8001A21
5-2.調(diào)用osRtxThreadWaitEnter前就緒隊列=200001D0中的線程: 20001774->200016B4->20001328
6-1.調(diào)用osRtxThreadWaitEnter->osRtxThreadDelayInsert將當(dāng)前運(yùn)行線程=20001834放到等待隊列
6-2.調(diào)用osRtxThreadWaitEnter->osRtxThreadListGet從就緒隊列獲取優(yōu)先級最高的線程=20001774
6-3.調(diào)用osRtxThreadWaitEnter->osRtxThreadSwitch將線程=20001774設(shè)置為激活態(tài)準(zhǔn)備運(yùn)行
7-1.調(diào)用osRtxThreadWaitEnter后等待隊列:2000136C->20001834->0
7-2.調(diào)用osRtxThreadWaitEnter后就緒隊列: 200016B4->20001328->0
(3)藍(lán)燈線程等待藍(lán)燈信號
藍(lán)燈線程通過執(zhí)行“Thread::signal_wait(BLUE_SIGNAL)”語句來等待藍(lán)燈信號BLUE_SIGNAL(0x42),在執(zhí)行該語句的過程中藍(lán)燈線程狀態(tài)由激活態(tài)更改為阻塞態(tài),放入到等待隊列中,然后取出就緒隊列中優(yōu)先級最高的紅燈線程,并將其激活運(yùn)行。
(4)紅燈線程設(shè)置綠燈信號
在紅燈線程中通過調(diào)用“thd_greenlight。signal_set(GREEN_SIGNAL)”函數(shù)來設(shè)置綠燈信號,此時mbedOS會將綠燈線程由等待隊列移出并將其放入到就緒隊列中?;诰€程優(yōu)先級相同的原因,此時綠燈線程并不會搶占當(dāng)前正在運(yùn)行的藍(lán)燈線程,而是會在SysTick中斷中通過輪詢調(diào)度的方式將綠燈線程激活運(yùn)行。
printf輸出結(jié)果如下:
1-1.當(dāng)前運(yùn)行的線程=200016B4 (紅燈),調(diào)用signal_set(GREEN_SIGNAL)設(shè)置綠燈等待線程信號0x47。
1-1-1.線程信號設(shè)置前的值=0
1-1-2.線程信號設(shè)置后的值=47
8-1.調(diào)用osRtxThreadWaitExit前等待隊列=200001E4中的程:2000136C->20001834->20001774
8-2.調(diào)用osRtxThreadWaitExit前就緒隊列=200001D0中的線程:20001328->0->8001A21
9-1.調(diào)用osRtxThreadWaitExit->osRtxThreadDelayRemove將線程=20001834從等待隊列中移出
9-2.調(diào)用osRtxThreadWaitExit->osRtxThreadReadyPut->osRtxThreadListPut將線程=20001834放到放到就緒隊列
10-1.調(diào)用osRtxThreadWaitExit后等待隊列:2000136C->20001774->0
10-2.調(diào)用osRtxThreadWaitExit后就緒隊列=200001D0中的線程:20001834->20001328->0
11.調(diào)用signal_set()結(jié)束。
(5)輪詢調(diào)度激活綠燈線程
在藍(lán)燈線程中設(shè)置完綠燈信號后,mbedOS內(nèi)部機(jī)制的SysTick中斷會每隔1 ms中斷一次并按照每個時間片(5 ms)為周期的方式對線程進(jìn)行輪詢調(diào)度,此時將激活綠燈線程運(yùn)行。
printf輸出結(jié)果如下:
12.進(jìn)入SysTick_Handler觸發(fā)osRtxTick_Handler對優(yōu)先級相同的線程進(jìn)行輪詢調(diào)度,將線程=20001834切換為激活態(tài)。
(6)綠燈線程獲得綠燈信號
綠燈線程在獲得綠燈信號后,會從等待隊列移出進(jìn)入就緒隊列,然后被激活運(yùn)行,實現(xiàn)切換綠燈亮暗,即執(zhí)行“Thread::signal_wait(GREEN_SIGNAL)”后續(xù)的語句。然后綠燈線程開始等待下一次的線程信號(即重復(fù)4-7步,如圖4所示),再激活紅燈線程運(yùn)行。
printf輸出結(jié)果如下:
2-2.當(dāng)前運(yùn)行的線程=20001834(綠燈)已等到線程信0x47,綠燈反轉(zhuǎn)。
2.當(dāng)前運(yùn)行的線程=20001834(綠燈)結(jié)束。
(7)紅燈線程設(shè)置藍(lán)燈信號
在紅燈線程中通過調(diào)用“thd_bluelight.signal_set(BLUE_SIGNAL)”函數(shù)來設(shè)置藍(lán)燈信號,此時mbedOS會將藍(lán)燈線程從等待隊列移出,此時線程狀態(tài)會由阻塞態(tài)更換為就緒態(tài),并放入到就緒隊列中。由于mbedOS對優(yōu)先級相同的線程采用輪詢調(diào)度策略,此時藍(lán)燈線程并不會搶占當(dāng)前正在運(yùn)行的紅燈線程,而是會在SysTick中斷中通過輪詢調(diào)度的方式將藍(lán)燈線程激活運(yùn)行。
(8)輪詢調(diào)度激活藍(lán)燈線程
在紅燈線程中設(shè)置完藍(lán)燈信號后,mbedOS內(nèi)部機(jī)制的SysTick中斷會每隔1 ms中斷一次并按照每個時間片(5 ms)為周期的方式對線程進(jìn)行輪詢調(diào)度,此時將會激活藍(lán)燈線程運(yùn)行。
(9)藍(lán)燈線程獲得藍(lán)燈信號
藍(lán)燈線程獲得藍(lán)燈信號后執(zhí)行“Thread::signal_wait(BLUE_SIGNAL)”后續(xù)的語句,實現(xiàn)切換藍(lán)燈亮暗。然后藍(lán)燈線程開始新一輪的等待信號(即重復(fù)9-13步,如圖4所示),再激活紅燈線程運(yùn)行。
本文闡述了mbedOS同步與通信手段——線程信號的響應(yīng)機(jī)制,并在STM32L431微控制器上進(jìn)行實驗測試,通過printf調(diào)試手段將線程信號工作原理的整個調(diào)度過程信息輸出到PC機(jī)中,并在mbedOS測試工程中以時序圖的方式進(jìn)行分析總結(jié)??梢宰屪x者更加透明地理解線程信號響應(yīng)的整個脈絡(luò)結(jié)構(gòu),不僅有助于從微觀的層面來理解RTOS的調(diào)度過程。同時,也為進(jìn)一步剖析RTOS的其它同步與通信方式提供了方法借鑒。后續(xù)將進(jìn)一步對RTOS的其它同步與通信方式進(jìn)行理解與分析。