劉中華 王宜懷 劉長(zhǎng)勇 王浩波
1(蘇州大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 江蘇 蘇州 215006)
2(武夷學(xué)院數(shù)學(xué)與計(jì)算機(jī)學(xué)院 福建 武夷山 354300)
隨著嵌入式實(shí)時(shí)操作系統(tǒng)(RTOS)[1-2]不斷發(fā)展,對(duì)于共享數(shù)據(jù)訪問(wèn)的不一致現(xiàn)象屢見(jiàn)不鮮,而多任務(wù)[3]的并發(fā)調(diào)度是造成這一現(xiàn)象的主要原因。面對(duì)操作系統(tǒng)的同步問(wèn)題,1968年荷蘭計(jì)算機(jī)科學(xué)家艾茲格·迪杰斯特拉提出了信號(hào)量(Semaphore)的概念[4-5],用來(lái)實(shí)現(xiàn)對(duì)操作系統(tǒng)的資源管理[6]和多任務(wù)調(diào)度。信號(hào)量機(jī)制在常用的RTOS中一直有被應(yīng)用,無(wú)論是早期出現(xiàn)的MQX,還是之后陸續(xù)出現(xiàn)的諸如μC/OS、FreeRTOS及2014年Arm公司出品的mbedOS等RTOS中,信號(hào)量機(jī)制始終被保留并不斷完善[7]。因此,充分理解信號(hào)量的調(diào)度機(jī)制,有助于開(kāi)發(fā)人員設(shè)計(jì)出實(shí)時(shí)性強(qiáng)、穩(wěn)定性好的RTOS。目前,有關(guān)操作系統(tǒng)的信號(hào)量機(jī)制剖析主要集中在Linux、FreeRTOS、VxWorks等操作系統(tǒng),并且不同的RTOS中信號(hào)量的名稱(chēng)和實(shí)現(xiàn)細(xì)節(jié)不太一樣,例如FreeRTOS有二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量、互斥量和遞歸互斥量,mbedOS只有互斥信號(hào)量和計(jì)數(shù)信號(hào)量;FreeRTOS中信號(hào)量的創(chuàng)建通過(guò)隊(duì)列實(shí)現(xiàn),mbedOS通過(guò)構(gòu)造結(jié)構(gòu)體來(lái)創(chuàng)建信號(hào)量[8]。但對(duì)mbedOS中的信號(hào)量調(diào)度剖析方面缺乏資料。為此,本文對(duì)mbedOS中的信號(hào)量調(diào)度機(jī)制進(jìn)行理論分析,重點(diǎn)剖析關(guān)鍵函數(shù)的實(shí)現(xiàn)原理并加以流程圖分析,利用STM32L431RC芯片結(jié)合SD-mbedOS工程框架[9]作為軟硬件環(huán)境,通過(guò)多個(gè)任務(wù)使用信號(hào)量機(jī)制的并行調(diào)度實(shí)驗(yàn),將實(shí)驗(yàn)的整個(gè)調(diào)度流程以及當(dāng)前所運(yùn)行的時(shí)間通過(guò)printf函數(shù)[10]進(jìn)行輸出顯示,最后對(duì)調(diào)度機(jī)制的理論執(zhí)行時(shí)間和實(shí)際執(zhí)行時(shí)間進(jìn)行對(duì)比,從而分析mbedOS信號(hào)量調(diào)度機(jī)制的實(shí)時(shí)性。通過(guò)對(duì)信號(hào)量調(diào)度機(jī)制進(jìn)行全面剖析并分析其實(shí)時(shí)性,有助于理解調(diào)度機(jī)制的執(zhí)行流程,更加了解多任務(wù)的并發(fā)調(diào)度機(jī)制,同時(shí)也為分析其他RTOS的信號(hào)量調(diào)度機(jī)制提供了基礎(chǔ)[11]。
在RTOS中,信號(hào)量通常被定義成一個(gè)提供信號(hào)的非負(fù)整型變量,來(lái)保證在多任務(wù)并發(fā)的環(huán)境下,能使得操作系統(tǒng)不會(huì)發(fā)生沖突,穩(wěn)定運(yùn)行。在操作系統(tǒng)的信號(hào)量機(jī)制的管理下,對(duì)共享資源的訪問(wèn)同步問(wèn)題都可以用信號(hào)量來(lái)實(shí)現(xiàn)。比如一個(gè)讀取數(shù)據(jù)任務(wù)和一個(gè)寫(xiě)入數(shù)據(jù)任務(wù)要訪問(wèn)共享資源緩沖區(qū)的問(wèn)題,就能通過(guò)三個(gè)信號(hào)量來(lái)實(shí)現(xiàn):SEM_Read,允許任務(wù)對(duì)緩沖區(qū)進(jìn)行讀取操作;SEM_Write,允許任務(wù)對(duì)緩存區(qū)進(jìn)行寫(xiě)入操作;SEM_Mutex,限制緩沖區(qū)的互斥訪問(wèn)。在同一時(shí)刻只能允許一個(gè)讀/寫(xiě)任務(wù)訪問(wèn)緩沖區(qū),對(duì)緩沖區(qū)進(jìn)行訪問(wèn)之前必須先獲取信號(hào)量SEM_Mutex,并且任務(wù)執(zhí)行完成后需釋放信號(hào)量[12]。在任何一個(gè)任務(wù)中,獲取信號(hào)量和釋放信號(hào)量是同時(shí)存在的,意味著在任務(wù)結(jié)束的時(shí)候,并不會(huì)占用信號(hào)量。在RTOS中,信號(hào)量的調(diào)度機(jī)制如圖1所示。
圖1 信號(hào)量調(diào)度的一般流程
正是信號(hào)量這種有序的特性,使得信號(hào)量能應(yīng)用到很多場(chǎng)合:多任務(wù)之間的同步進(jìn)行;對(duì)共享資源的訪問(wèn);為了實(shí)現(xiàn)更好的性能而控制任務(wù)的并發(fā)數(shù)等。
在RTOS中的同步與通信機(jī)制中,與設(shè)置事件字來(lái)表達(dá)多種可能的情況相比,信號(hào)量是一種簡(jiǎn)單的同步手段。
采用信號(hào)量作為任務(wù)與任務(wù)間或中斷與任務(wù)間的同步與通信的方法時(shí),則必定有任務(wù)(或中斷)創(chuàng)建信號(hào)量,同時(shí)有任務(wù)等待獲取信號(hào)量[13]。信號(hào)量的獲取與釋放必須在同一任務(wù)中,例如在mbedOS中,任務(wù)調(diào)用Wait()函數(shù)獲取信號(hào)量,實(shí)際是通過(guò)判斷信號(hào)量控制塊結(jié)構(gòu)體的Tokens變量來(lái)決定是否允許獲取信號(hào)量;在FreeRTOS中則是調(diào)用xSemaphoreTake()函數(shù)來(lái)獲取信號(hào)量,判斷隊(duì)列句柄xHandle中的uxMessageWaiting變量來(lái)決定是否允許獲取信號(hào)量。在任務(wù)執(zhí)行操作完成后,會(huì)將信號(hào)量釋放,例如在mbedOS中通過(guò)調(diào)用Release()函數(shù)來(lái)釋放信號(hào)量;在FreeRTOS中調(diào)用xSemaphoreGive()函數(shù)來(lái)釋放信號(hào)量[14]。若當(dāng)前等待隊(duì)列存在任務(wù)因等待獲取信號(hào)量而阻塞,則會(huì)將等待隊(duì)列中的優(yōu)先級(jí)最高的任務(wù)移入就緒隊(duì)列等待調(diào)度。
信號(hào)量作為RTOS中任務(wù)同步與通信的重要方法之一,其主要功能是實(shí)現(xiàn)任務(wù)之間的同步或多任務(wù)并發(fā)執(zhí)行。在信號(hào)量調(diào)度機(jī)制過(guò)程中所涉及到的關(guān)鍵要素有信號(hào)量的創(chuàng)建、獲取、釋放、響應(yīng)、調(diào)度等[15]。
(1) 信號(hào)量的創(chuàng)建:指明信號(hào)量的名稱(chēng),初始化信號(hào)量控制塊結(jié)構(gòu)體并設(shè)置信號(hào)量數(shù)值的大小。
(2) 信號(hào)量的獲?。褐该髂膫€(gè)任務(wù)或中斷中請(qǐng)求獲取信號(hào)量,等待獲取信號(hào)量的時(shí)間為多少。
(3) 信號(hào)量的釋放:在任務(wù)獲取到信號(hào)量并執(zhí)行完相關(guān)操作之后,釋放信號(hào)量,若信號(hào)量的等待隊(duì)列不為空,則取出任務(wù)準(zhǔn)備進(jìn)行調(diào)度。
(4) 信號(hào)量的響應(yīng):當(dāng)信號(hào)量被獲取后,獲取信號(hào)量的任務(wù)會(huì)繼續(xù)往下執(zhí)行,當(dāng)操作完成后,會(huì)釋放信號(hào)量。
(5) 信號(hào)量的調(diào)度:當(dāng)有任務(wù)釋放信號(hào)量時(shí),會(huì)將等待隊(duì)列中優(yōu)先級(jí)最高的任務(wù)與正在運(yùn)行的任務(wù)的優(yōu)先級(jí)進(jìn)行比較,判斷是否需要重新進(jìn)行任務(wù)調(diào)度。
mbedOS信號(hào)量機(jī)制首先從創(chuàng)建信號(hào)量開(kāi)始,從程序開(kāi)始運(yùn)行到主任務(wù)執(zhí)行app_init()函數(shù)后,會(huì)調(diào)用Semaphore()函數(shù)來(lái)創(chuàng)建信號(hào)量。任務(wù)可以分別調(diào)用Wait()函數(shù)和Release()函數(shù)來(lái)進(jìn)行信號(hào)量的獲取和釋放[16]。
下面將著重分析信號(hào)量創(chuàng)建、信號(hào)量獲取和信號(hào)量釋放的過(guò)程以及函數(shù)調(diào)用。
在mbedOS中使用信號(hào)量控制塊結(jié)構(gòu)體來(lái)描述信號(hào)量,數(shù)據(jù)結(jié)構(gòu)如下:
typedef struct{
uint8_t
id;//信號(hào)量ID
uint8_t reserved_state;
//互斥量狀態(tài)
uint8_t
flags;//信號(hào)量標(biāo)志
uint8_t reserved;
const char
*name;//信號(hào)量名稱(chēng)
osRtxThread_t *thread_list;
//信號(hào)量等待隊(duì)列
uint16_t
tokens;//當(dāng)前信號(hào)量的數(shù)值
uint16_t max_tokens;
//信號(hào)量的最大數(shù)值
}osRtxSemaphore_t;
信號(hào)量創(chuàng)建函數(shù)調(diào)用順序?yàn)镾emaphore()→Constructor()→osSemaphoreNew()→_svcSemaphoreNew()→SVC_Handler()→svcRtxSemaphoreNew()。信號(hào)量創(chuàng)建的流程如圖2所示。
圖2 信號(hào)量創(chuàng)建的流程
信號(hào)量的創(chuàng)建調(diào)用Semaphore()函數(shù),傳入?yún)?shù)count表示創(chuàng)建信號(hào)量的數(shù)值大小。緊接著調(diào)用Constructor()函數(shù),在該函數(shù)中初始化信號(hào)量屬性結(jié)構(gòu)體osSemaphoreAttr_t和信號(hào)量控制塊結(jié)構(gòu)體osRtxSemaphore_t。當(dāng)初始化結(jié)構(gòu)體后,調(diào)用osSemaphoreNew()函數(shù)來(lái)創(chuàng)建信號(hào)量。在任務(wù)模式下會(huì)調(diào)用_svcSemaphoreNew()函數(shù),從而觸發(fā)SVC中斷,轉(zhuǎn)而去執(zhí)行SVC_Handler中斷處理函數(shù)。然后實(shí)際執(zhí)行的函數(shù)是svcRtxSemaphoreNew(),由該函數(shù)來(lái)執(zhí)行信號(hào)量的創(chuàng)建。當(dāng)信號(hào)量創(chuàng)建之后,會(huì)對(duì)信號(hào)量等待隊(duì)列thread_list是否為空進(jìn)行判斷,若不為空,則說(shuō)明存在任務(wù)等待獲取信號(hào)量,則從信號(hào)量等待隊(duì)列中取出優(yōu)先級(jí)最高的任務(wù)放入就緒隊(duì)列,等待調(diào)度[17]。
信號(hào)量獲取函數(shù)調(diào)用順序?yàn)閃ait()→OsSemaphoreAcquire()→_svcSemaphoreAcquire()→SVC_Handler()→svcRtxSemaphoreAcquire()。信號(hào)量獲取的流程如圖3所示。
圖3 信號(hào)量獲取的流程
信號(hào)量獲取通過(guò)調(diào)用Wait()函數(shù),傳入?yún)?shù)millisec設(shè)置等待信號(hào)量的時(shí)間,在該函數(shù)中調(diào)用_wait()函數(shù),然后再調(diào)用osSemaphoreAcquire()函數(shù)。由于處于任務(wù)模式下,則會(huì)調(diào)用_svcSemaphoreAcquire()函數(shù),在該函數(shù)中會(huì)觸發(fā)SVC中斷,轉(zhuǎn)而去執(zhí)行SVC_Handler中斷處理函數(shù)。而實(shí)際執(zhí)行的是svcRtxSemaphoreAcquire()函數(shù),在函數(shù)內(nèi)部來(lái)判斷Tokens的數(shù)值是否大于0,若大于0,則表示任務(wù)可以獲取信號(hào)量,此時(shí)首先要屏蔽系統(tǒng)中斷,然后對(duì)信號(hào)量的數(shù)值進(jìn)行減一操作,否則可能會(huì)多任務(wù)訪問(wèn)信號(hào)量數(shù)據(jù)出現(xiàn)不一致;若不大于0,則會(huì)根據(jù)參數(shù)millisec進(jìn)行阻塞當(dāng)前任務(wù)或者返回獲取信號(hào)量失敗。
信號(hào)量釋放函數(shù)調(diào)用順序?yàn)镽elease()→OsSemaphoreRelease()→_svcSemaphoreRelease()→SVC_Handler()→svcRtxSemaphoreRelease()。信號(hào)量釋放的流程如圖4所示。
圖4 信號(hào)量釋放的流程
信號(hào)量的釋放和信號(hào)量獲取的過(guò)程大致相同。首先調(diào)用Release()函數(shù),請(qǐng)求釋放信號(hào)量,然后會(huì)跳轉(zhuǎn)到osSemaphoreRelease()函數(shù)。當(dāng)前處于任務(wù)模式下,則會(huì)調(diào)用_svcSemaphoreRelease()函數(shù),從而觸發(fā)SVC中斷。而實(shí)際調(diào)用的是svcRtxSemaphoreRelease()函數(shù),在該函數(shù)的執(zhí)行過(guò)程中,對(duì)信號(hào)量阻塞隊(duì)列進(jìn)行判斷,若為空,則直接調(diào)用SemaphoreTokenIncrement()函數(shù)進(jìn)行釋放信號(hào)量;若不為空,則調(diào)用osRtxThreadListGet()函數(shù)喚醒隊(duì)列中優(yōu)先級(jí)最高的任務(wù),重新進(jìn)行任務(wù)調(diào)度。
以ARM Cortex-M4為內(nèi)核的STM32L431RC開(kāi)發(fā)芯片結(jié)合意法半導(dǎo)體(ST)公司研發(fā)了STM32CubeIDE為開(kāi)發(fā)環(huán)境對(duì)mbedOS中的信號(hào)量調(diào)度機(jī)制進(jìn)行實(shí)踐。STM32L431RC芯片為64引腳LQFP封裝,Flash內(nèi)存為256 KB(共有128個(gè)扇區(qū)),RAM內(nèi)存為64 KB。在信號(hào)量調(diào)度機(jī)制的實(shí)踐中,使用了printf打樁輸出調(diào)試方法,對(duì)關(guān)鍵步驟進(jìn)行文字輸出,可以更好地了解整個(gè)程序的運(yùn)行。
在SD-mbedOS工程框架下創(chuàng)建工程實(shí)例,實(shí)例的功能是:創(chuàng)建了三個(gè)優(yōu)先級(jí)相同的任務(wù)Td1、Td2和Td3,數(shù)值為2的信號(hào)量SP,按照Td1、Td2和Td3的順序啟動(dòng)三個(gè)任務(wù)。在Td1任務(wù)中,先請(qǐng)求獲取信號(hào)量,獲取成功后Td1任務(wù)延時(shí)5 s;在Td2任務(wù)中,獲取信號(hào)量成功后,延時(shí)2 s。在Td3任務(wù)中,獲取信號(hào)量后,延時(shí)5 s,然后切換STM32L431RC芯片上的綠燈的亮暗。在信號(hào)量獲取和釋放的前后,輸出當(dāng)前系統(tǒng)的運(yùn)行時(shí)間,以便算出實(shí)際執(zhí)行時(shí)間。三個(gè)任務(wù)(Td1、Td2和Td3)的內(nèi)存地址分別為0x200016BC、0x2000177C和0x2000183C。實(shí)例的功能流程如圖5所示。
圖5 實(shí)例工程的功能流程
結(jié)合實(shí)例對(duì)mbedOS中信號(hào)量機(jī)制的調(diào)度過(guò)程進(jìn)行更細(xì)致的分析,將當(dāng)前運(yùn)行的任務(wù)、任務(wù)的狀態(tài)、系統(tǒng)所執(zhí)行的時(shí)間用printf函數(shù)的方式進(jìn)行輸出。
(1) 任務(wù)啟動(dòng)。芯片上電啟動(dòng)最后轉(zhuǎn)到主任務(wù)函數(shù)中執(zhí)行,先后啟動(dòng)三個(gè)任務(wù),然后阻塞該函數(shù)的運(yùn)行,由mbedOS負(fù)責(zé)對(duì)任務(wù)的調(diào)度運(yùn)行。printf輸出結(jié)果如下(下同):
Td1、Td2和Td3任務(wù)啟動(dòng)完成,同時(shí)阻塞主任務(wù)。
(2) Td1任務(wù)請(qǐng)求獲取信號(hào)量。在主任務(wù)阻塞后,mbedOS從就緒隊(duì)列中取出優(yōu)先級(jí)最高的任務(wù)(此時(shí)為T(mén)d1)開(kāi)始執(zhí)行。任務(wù)啟動(dòng)后請(qǐng)求獲取信號(hào)量,初始信號(hào)量數(shù)值為2,Td1任務(wù)獲取信號(hào)量成功,信號(hào)量數(shù)值減2變?yōu)?。
Td1任務(wù)(200016BC)請(qǐng)求獲取SP,當(dāng)前時(shí)間:3.441 44 s。
SP=2!=0,表示當(dāng)前任務(wù)(200016BC)可獲取SP。
Td1任務(wù)獲取SP成功,當(dāng)前時(shí)間:3.445 627 s,延時(shí)5 s。
(3) Td2任務(wù)請(qǐng)求獲取信號(hào)量。當(dāng)前信號(hào)量SP的數(shù)值為1,Td2任務(wù)可以獲取信號(hào)量SP。
Td2任務(wù)(2000177C)請(qǐng)求獲取SP,當(dāng)前時(shí)間:3.447 029 s。
SP=1!=0,表示當(dāng)前任務(wù)(2000177C)可獲取SP。
Td2任務(wù)獲取SP成功,當(dāng)前時(shí)間:3.461 119 s,延時(shí)2 s。
(4) Td3任務(wù)請(qǐng)求獲取信號(hào)量。由于當(dāng)前SP的數(shù)值為0,Td3任務(wù)請(qǐng)求獲取信號(hào)量失敗,會(huì)將Td3任務(wù)添加到信號(hào)量阻塞隊(duì)列和延時(shí)等待隊(duì)列中。
Td3任務(wù)(2000183C)請(qǐng)求獲取SP,當(dāng)前時(shí)間:3.452 028 s。
SP=0,表示當(dāng)前任務(wù)(2000183C)獲取SP失敗。
將當(dāng)前任務(wù)(2000183C)放入等待隊(duì)列和SP阻塞隊(duì)列,獲取就緒隊(duì)列中的任務(wù),當(dāng)前時(shí)間:3.466 121 s。
(5) Td2任務(wù)釋放信號(hào)量。當(dāng)信號(hào)量SP被Td1和Td2獲取之后,在Td2任務(wù)延時(shí)2 s后會(huì)釋放信號(hào)量,由于在信號(hào)量阻塞隊(duì)列中有一個(gè)Td3任務(wù)等待獲取信號(hào)量,因此,在Td2任務(wù)釋放信號(hào)量之后,會(huì)將Td3任務(wù)從延時(shí)等待隊(duì)列和信號(hào)量阻塞隊(duì)列中取出,并放入就緒隊(duì)列中準(zhǔn)備運(yùn)行。此時(shí)Td3任務(wù)已經(jīng)獲取到信號(hào)量,可以看成是Td2任務(wù)將信號(hào)量轉(zhuǎn)移給Td3任務(wù),當(dāng)前信號(hào)量數(shù)值還是為0。
Td2任務(wù)釋放SP,當(dāng)前時(shí)間:8.053 098 s。
從等待隊(duì)列和SP阻塞隊(duì)列中獲取等待SP的任務(wù)(2000183C),當(dāng)前時(shí)間:8.055 977 s。
Td2任務(wù)釋放SP成功,當(dāng)前時(shí)間:8.056 314 s。
Td3任務(wù)獲取SP成功,當(dāng)前時(shí)間:8.062 021 s,延時(shí)5 s并切換綠燈亮暗。
(6) Td2任務(wù)開(kāi)始新一輪的請(qǐng)求獲取信號(hào)量。Td2任務(wù)釋放信號(hào)量后,重新開(kāi)始獲取信號(hào)量SP,此時(shí)信號(hào)量被Td1任務(wù)和Td3任務(wù)占據(jù),信號(hào)量數(shù)值為0。因此,Td2任務(wù)放入信號(hào)量阻塞隊(duì)列和延時(shí)等待隊(duì)列中,同時(shí)從就緒隊(duì)列中取出Td1任務(wù)準(zhǔn)備運(yùn)行。
Td2任務(wù)(2000177C)請(qǐng)求獲取SP,當(dāng)前時(shí)間:11.505 674 s。
SP=0,表示當(dāng)前任務(wù)(2000177C)獲取SP失敗。
將當(dāng)前任務(wù)(2000177C)放入等待隊(duì)列和SP阻塞隊(duì)列,獲取就緒隊(duì)列中的任務(wù),當(dāng)前時(shí)間:11.519 806 s。
(7) Td1任務(wù)釋放信號(hào)量。Td1任務(wù)延時(shí)5 s結(jié)束,釋放信號(hào)量。此時(shí)信號(hào)量阻塞隊(duì)列中有Td2任務(wù)在等待獲取信號(hào)量,當(dāng)Td1任務(wù)釋放信號(hào)量之后,將Td2任務(wù)從延時(shí)等待隊(duì)列和信號(hào)量阻塞隊(duì)列中取出,并放入就緒隊(duì)列中準(zhǔn)備運(yùn)行。
Td1任務(wù)釋放SP,當(dāng)前時(shí)間:16.074 655 s。
從等待隊(duì)列和SP阻塞隊(duì)列中獲取等待SP的任務(wù)(2000177C),當(dāng)前時(shí)間:16.082 538 s。
Td1任務(wù)釋放SP成功,當(dāng)前時(shí)間:16.083 962 s。
Td2任務(wù)獲取SP成功,當(dāng)前時(shí)間:16.090 021 s,延時(shí)2 s。
(8) Td1任務(wù)開(kāi)始新一輪的請(qǐng)求獲取信號(hào)量SP。Td1任務(wù)請(qǐng)求獲取信號(hào)量SP,當(dāng)前SP數(shù)值為0,將Td1任務(wù)放入延時(shí)等待隊(duì)列和信號(hào)量阻塞隊(duì)列中。
Td1任務(wù)(200016BC)請(qǐng)求獲取SP,當(dāng)前時(shí)間:19.533 285 s。
SP=0,表示當(dāng)前任務(wù)(200016BC)獲取SP失敗。
將當(dāng)前任務(wù)(200016BC)放入等待隊(duì)列和SP阻塞隊(duì)列,獲取就緒隊(duì)列中的任務(wù),當(dāng)前時(shí)間:19.547 460 s。
(9) Td2和Td3任務(wù)釋放信號(hào)量。Td2任務(wù)延時(shí)結(jié)束后,釋放信號(hào)量。同時(shí)將Td1任務(wù)從延時(shí)等待隊(duì)列和信號(hào)量阻塞隊(duì)列中移出,并放入就緒隊(duì)列中運(yùn)行。在Td2任務(wù)釋放信號(hào)量后,Td3任務(wù)延時(shí)結(jié)束釋放信號(hào)量(幾乎可以看作同時(shí)),此時(shí)信號(hào)量數(shù)值為1,故Td2獲取信號(hào)量成功,開(kāi)始運(yùn)行。
Td2任務(wù)釋放SP,當(dāng)前時(shí)間:21.834 034 s。
從等待隊(duì)列和SP阻塞隊(duì)列中獲取等待SP的任務(wù)(200016BC),當(dāng)前時(shí)間:21.836 s。
Td2任務(wù)釋放SP成功,當(dāng)前時(shí)間:21.837 424 s。
Td3任務(wù)釋放SP,當(dāng)前時(shí)間:21.838 129 s。
Td3任務(wù)釋放SP成功,當(dāng)前時(shí)間:21.841 097 s。
Td1任務(wù)獲取SP成功,當(dāng)前時(shí)間:21.843 022 s,延時(shí)5 s。
(10) Td1、Td2和Td3任務(wù)新一輪的請(qǐng)求獲取信號(hào)量。此時(shí)開(kāi)始的運(yùn)行情況和之前一樣,循環(huán)之前的過(guò)程。按照Td1、Td2和Td3的順序反復(fù)獲取信號(hào)量執(zhí)行。任務(wù)的調(diào)度時(shí)序圖如圖6所示。
圖6 基于信號(hào)量機(jī)制的任務(wù)調(diào)度時(shí)序圖
任務(wù)信號(hào)量的獲取和釋放的理論時(shí)間是判斷mbedOS中信號(hào)量機(jī)制的實(shí)時(shí)性好與壞的性能標(biāo)準(zhǔn)。在SD-mbedOS架構(gòu)下,系統(tǒng)時(shí)鐘頻率為48 MHz,一個(gè)指令周期的時(shí)間為0.020 8 μs。以任務(wù)請(qǐng)求獲取信號(hào)量為例,進(jìn)行理論時(shí)間和實(shí)際執(zhí)行時(shí)間的比較,在信號(hào)量數(shù)值不為0的情況下,任務(wù)申請(qǐng)獲取信號(hào)量的機(jī)器指令有461條,機(jī)器指令的條數(shù)是以執(zhí)行一條_NOP指令所花費(fèi)的時(shí)間為基準(zhǔn),所有執(zhí)行的機(jī)器指令都能在編譯之后生成的.lst文件中找到,關(guān)鍵函數(shù)及其對(duì)應(yīng)的機(jī)器碼和匯編指令如表1所示。
表1 關(guān)鍵函數(shù)及其對(duì)應(yīng)的機(jī)器碼和匯編指令
根據(jù)計(jì)算得:信號(hào)量獲取的理論時(shí)間為10.44 μs,而在單個(gè)任務(wù)執(zhí)行的情況下,信號(hào)量獲取(信號(hào)量數(shù)值不為0)的實(shí)際執(zhí)行時(shí)間為14.8 μs,理論時(shí)間和實(shí)際時(shí)間的誤差在微秒級(jí)別,誤差在可接受的范圍內(nèi)。
在工程實(shí)例中,將任務(wù)請(qǐng)求獲取信號(hào)量前后、釋放信號(hào)量前后的系統(tǒng)運(yùn)行時(shí)間輸出。三個(gè)任務(wù)具體的調(diào)度時(shí)間如表2所示。
表2 信號(hào)量獲取和釋放的實(shí)際執(zhí)行時(shí)間 單位:ms
表2中獲取信號(hào)量I和獲取信號(hào)量II分別表示:獲取信號(hào)量時(shí)信號(hào)量數(shù)值不為0和為0,獲取信號(hào)量II中的時(shí)間I表示信號(hào)量數(shù)值為0,將任務(wù)添加到相應(yīng)隊(duì)列的時(shí)間,時(shí)間II表示在任務(wù)添加到隊(duì)列中后,到獲取信號(hào)量成功的時(shí)間。釋放信號(hào)量I和釋放信號(hào)量II分別表示:釋放信號(hào)量時(shí)信號(hào)量阻塞隊(duì)列為空和不為空,而時(shí)間III表示從隊(duì)列中移出任務(wù)的時(shí)間,時(shí)間IV表示其他時(shí)間。
表2中的時(shí)間是結(jié)合實(shí)例工程中三個(gè)任務(wù)的延遲時(shí)間計(jì)算的,由于實(shí)例中是多任務(wù)并發(fā),并且系統(tǒng)的運(yùn)行狀態(tài)用printf方法進(jìn)行輸出,故信號(hào)量調(diào)度機(jī)制中的操作耗時(shí)較多。總的來(lái)看,信號(hào)量的獲取和釋放需要的時(shí)間很短,具有很好的實(shí)時(shí)性。
mbedOS的信號(hào)量調(diào)度機(jī)制是一個(gè)較為復(fù)雜的過(guò)程,其中涉及到多任務(wù)并發(fā)調(diào)度、任務(wù)對(duì)信號(hào)量的獲取和釋放、就緒隊(duì)列和等待隊(duì)列等的管理,其中的函數(shù)調(diào)用關(guān)系也較為復(fù)雜,觸發(fā)到的中斷函數(shù)有SVC中斷和Systick中斷等。本文重點(diǎn)剖析mbedOS中的信號(hào)量調(diào)度機(jī)制及其關(guān)鍵函數(shù),加以流程圖總結(jié),通過(guò)多任務(wù)并發(fā)的調(diào)度實(shí)驗(yàn),將調(diào)度過(guò)程中任務(wù)的切換、狀態(tài)的變化、當(dāng)前系統(tǒng)運(yùn)行時(shí)間進(jìn)行輸出,給出時(shí)序圖分析,進(jìn)一步驗(yàn)證信號(hào)量調(diào)度機(jī)制理論分析的正確性,最后還對(duì)調(diào)度過(guò)程進(jìn)行實(shí)時(shí)性能剖析,結(jié)果表明信號(hào)量調(diào)度機(jī)制的實(shí)時(shí)性能較好。通過(guò)對(duì)信號(hào)量調(diào)度機(jī)制的剖析,有助于更好地理解mbedOS的多任務(wù)并發(fā)機(jī)制,也為其他RTOS的信號(hào)量機(jī)制分析提供了基礎(chǔ)。