淺析μC/OS-ⅡAPI的設計思想及實(shí)現機制
void MyTask (void *pdata)
函數參數為一指針變量,指向對應任務(wù)的OS_TCB結構地址。本函數是有用的調試工具。
3. 消息和同步類(lèi)API的設計思路和實(shí)現機制
μC/OS-Ⅱ中有三種方法實(shí)現消息通信和同步:信號量、郵箱和消息隊列。一個(gè)任務(wù)或者中斷服務(wù)子程序可以通過(guò)事件控制塊ECB(Event Control Blocks)來(lái)向另外的任務(wù)發(fā)信號。這里,所有的信號都被看成是事件(Event)。這也說(shuō)明為什么上面把用于通訊的數據結構叫做事件控制塊。一個(gè)任務(wù)還可以等待另一個(gè)任務(wù)或中斷服務(wù)子程序給它發(fā)送信號。這里要注意的是,只有任務(wù)可以等待事件發(fā)生,中斷服務(wù)子程序是不能這樣做的。對于處于等待狀態(tài)的任務(wù),還可以給它指定一個(gè)最長(cháng)等待時(shí)間,以此來(lái)防止因為等待的事件沒(méi)有發(fā)生而無(wú)限期地等下去。多個(gè)任務(wù)可以同時(shí)等待同一個(gè)事件的發(fā)生。在這種情況下,當該事件發(fā)生后,所有等待該事件的任務(wù)中,優(yōu)先級最高的任務(wù)得到了該事件并進(jìn)入就緒狀態(tài),準備執行。上面講到的事件,可以是信號量、郵箱或者消息隊列等。當事件控制塊是一個(gè)信號量時(shí),任務(wù)可以等待它,也可以給它發(fā)送消息。
μC/OS-II中的信號量由兩部分組成:一個(gè)是信號量的計數值,它是一個(gè)16位的無(wú)符號整數(0 到65,535之間);另一個(gè)是由等待該信號量的任務(wù)組成的等待任務(wù)表。用戶(hù)要在OS_CFG.H中將OS_SEM_EN開(kāi)關(guān)量常數置成1,這樣μC/OS-II才能支持信號量。
郵箱是μC/OS-II中另一種通訊機制,它可以使一個(gè)任務(wù)或者中斷服務(wù)子程序向另一個(gè)任務(wù)發(fā)送一個(gè)指針型的變量。該指針指向一個(gè)包含了特定“消息”的數據結構。為了在μC/OS-II中使用郵箱,必須將OS_CFG.H中的OS_MBOX_EN常數置為1。
消息隊列是μC/OS-II中另一種通訊機制,它可以使一個(gè)任務(wù)或者中斷服務(wù)子程序向另一個(gè)任務(wù)發(fā)送以指針?lè )绞蕉x的變量。因具體的應用有所不同,每個(gè)指針指向的數據結構變量也有所不同。為了使用μC/OS-II的消息隊列功能,需要在OS_CFG.H 文件中,將OS_Q_EN常數設置為1,并且通過(guò)常數OS_MAX_QS來(lái)決定μC/OS-II支持的最多消息隊列數。
μC/OS-Ⅱ提供一系列API函數供用戶(hù)調用,實(shí)現各個(gè)任務(wù)之間的通信和同步功能。下面以信號量為例說(shuō)明各個(gè)API的實(shí)現。
μC/OS-II提供了5個(gè)對信號量進(jìn)行操作的函數。它們是:OSSemCreate(),OSSemPend(),OSSemPost(),OSSemAccept()和OSSemQuery()函數。圖 F6.5說(shuō)明了任務(wù)、中斷服務(wù)子程序和信號量之間的關(guān)系。圖中用鑰匙或者旗幟的符號來(lái)表示信號量:如果信號量用于對共享資源的訪(fǎng)問(wèn),那么信號量就用鑰匙符號。符號旁邊的數字N代表可用資源數。對于二值信號量,該值就是1;如果信號量用于表示某事件的發(fā)生,那么就用旗幟符號。這時(shí)的數字N代表事件已經(jīng)發(fā)生的次數。從圖 F6.5中可以看出OSSemPost()函數可以由任務(wù)或者中斷服務(wù)子程序調用,而OSSemPend()和OSSemQuery()函數只能有任務(wù)程序調用。
3.1建立一個(gè)信號量, OSSemCreate()
OS_EVENT *OSSemCreate (INT16U cnt)
函數參數傳遞的是要創(chuàng )建的信號量的初始值,在函數內部對任務(wù)控制塊進(jìn)行初始化。OSSemCreate()返回給調用函數一個(gè)指向任務(wù)控制塊的指針。以后對信號量的所有操作,如OSSemPend(), OSSemPost(), OSSemAccept()和OSSemQuery()都是通過(guò)該指針完成的。因此,這個(gè)指針實(shí)際上就是該信號量的句柄。如果系統中沒(méi)有可用的任務(wù)控制塊,OSSemCreate()將返回一個(gè)NULL指針。
值得注意的是,在μC/OS-II中,信號量一旦建立就不能刪除了,因此也就不可能將一個(gè)已分配的任務(wù)控制塊再放回到空閑ECB鏈表中。如果有任務(wù)正在等待某個(gè)信號量,或者某任務(wù)的運行依賴(lài)于某信號量的出現時(shí),刪除該任務(wù)是很危險的。
3.2等待一個(gè)信號量, OSSemPend()
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
它首先檢查指針pevent所指的任務(wù)控制塊是否是由OSSemCreate()建立的。如果信號量當前是可用的(信號量的計數值大于0),將信號量的計數值減1,然后函數將“無(wú)錯”錯誤代碼返回給它的調用函數。顯然,如果正在等待信號量,這時(shí)的輸出正是我們所希望的,也是運行OSSemPend()函數最快的路徑。
3.3發(fā)送一個(gè)信號量, OSSemPost()
INT8U OSSemPost (OS_EVENT *pevent)
它首先檢查參數指針pevent指向的任務(wù)控制塊是否是OSSemCreate()函數建立的,接著(zhù)檢查是否有任務(wù)在等待該信號量。如果該任務(wù)控制塊中的.OSEventGrp域不是0,說(shuō)明有任務(wù)正在等待該信號量。這時(shí),就要調用函數OSEventTaskRdy(),使一個(gè)任務(wù)進(jìn)入就緒狀態(tài),把其中的最高優(yōu)先級任務(wù)從等待任務(wù)列表中刪除并使它進(jìn)入就緒狀態(tài)。然后,調用OSSched()任務(wù)調度函數檢查該任務(wù)是否是系統中的最高優(yōu)先級的就緒任務(wù)。如果是,這時(shí)就要進(jìn)行任務(wù)切換[當OSSemPost()函數是在任務(wù)中調用的],準備執行該就緒任務(wù)。如果不是,OSSched()直接返回,調用OSSemPost()的任務(wù)得以繼續執行。如果這時(shí)沒(méi)有任務(wù)在等待該信號量,該信號量的計數值就簡(jiǎn)單地加1。
上面是由任務(wù)調用OSSemPost()時(shí)的情況。當中斷服務(wù)子程序調用該函數時(shí),不會(huì )發(fā)生上面的任務(wù)切換。如果需要,任務(wù)切換要等到中斷嵌套的最外層中斷服務(wù)子程序調用OSIntExit()函數后才能進(jìn)行。
3.4無(wú)等待地請求一個(gè)信號量, OSSemAccept()
INT16U OSSemAccept (OS_EVENT *pevent)
當一個(gè)任務(wù)請求一個(gè)信號量時(shí),如果該信號量暫時(shí)無(wú)效,也可以讓該任務(wù)簡(jiǎn)單地返回,而不是進(jìn)入睡眠等待狀態(tài)。這種情況下的操作是由OSSemAccept()函數完成的。該函數在最開(kāi)始也是檢查參數指針pevent指向的事件控制塊是否是由OSSemCreate()函數建立的,接著(zhù)從該信號量的事件控制塊中取出當前計數值,并檢查該信號量是否有效(計數值是否為非0值)。如果有效,則將信號量的計數值減1,然后將信號量的原有計數值返回給調用函數。調用函數需要對該返回值進(jìn)行檢查。如果該值是0,說(shuō)明該信號量無(wú)效。如果該值大于0,說(shuō)明該信號量有效,同時(shí)該值也暗示著(zhù)該信號量當前可用的資源數。應該注意的是,這些可用資源中,已經(jīng)被該調用函數自身占用了一個(gè)(該計數值已經(jīng)被減1)。中斷服務(wù)子程序要請求信號量時(shí),只能用OSSemAccept()而不能用OSSemPend(),因為中斷服務(wù)子程序是不允許等待的。
評論