μC/OS-II的任務(wù)之間的通訊與同步
在μC/OS-II中,有多種方法可以保護任務(wù)之間的共享數(shù)據(jù)和提供任務(wù)之間的通訊。在前面的章節(jié)中,已經(jīng)講到了其中的兩種:
本文引用地址:http://www.ex-cimer.com/article/201610/305741.htm一是利用宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()來關(guān)閉中斷和打開中斷。當(dāng)兩個任務(wù)或者一個任務(wù)和一個中斷服務(wù)子程序共享某些數(shù)據(jù)時,可以采用這種方法,詳見3.00節(jié)臨界段、8.03.02節(jié) OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL()及9.03.02節(jié)臨界段,OS_CPU.H;
二是利用函數(shù)OSSchedLock()和OSSchekUnlock()對μC/OS-II中的任務(wù)調(diào)度函數(shù)上鎖和開鎖。用這種方法也可以實現(xiàn)數(shù)據(jù)的共享,詳見3.06節(jié) 給調(diào)度器上鎖和開鎖。
本章將介紹另外三種用于數(shù)據(jù)共享和任務(wù)通訊的方法:信號量、郵箱和消息隊列。
圖F6.1介紹了任務(wù)和中斷服務(wù)子程序之間是如何進行通訊的。
一個任務(wù)或者中斷服務(wù)子程序可以通過事件控制塊ECB(EventCONtrolBlocks)來向另外的任務(wù)發(fā)信號[F6.1A(1)]。這里,所有的信號都被看成是事件(Event)。這也說明為什么上面把用于通訊的數(shù)據(jù)結(jié)構(gòu)叫做事件控制塊。一個任務(wù)還可以等待另一個任務(wù)或中斷服務(wù)子程序給它發(fā)送信號[F6.1A(2)]。這里要注意的是,只有任務(wù)可以等待事件發(fā)生,中斷服務(wù)子程序是不能這樣做的。對于處于等待狀態(tài)的任務(wù),還可以給它指定一個最長等待時間,以此來防止因為等待的事件沒有發(fā)生而無限期地等下去。
多個任務(wù)可以同時等待同一個事件的發(fā)生[F6.1B]。在這種情況下,當(dāng)該事件發(fā)生后,所有等待該事件的任務(wù)中,優(yōu)先級最高的任務(wù)得到了該事件并進入就緒狀態(tài),準(zhǔn)備執(zhí)行。上面講到的事件,可以是信號量、郵箱或者消息隊列等。當(dāng)事件控制塊是一個信號量時,任務(wù)可以等待它,也可以給它發(fā)送消息。
圖6.1事件控制塊的使用
6.1 事件控制塊ECB
μC/OS-II通過uCOS_II.H中定義的OS_EVENT數(shù)據(jù)結(jié)構(gòu)來維護一個事件控制塊的所有信息[程序清單L6.1],也就是本章開篇講到的事件控制塊ECB。該結(jié)構(gòu)中除了包含了事件本身的定義,如用于信號量的計數(shù)器,用于指向郵箱的指針,以及指向消息隊列的指針數(shù)組等,還定義了等待該事件的所有任務(wù)的列表。程序清單L6.1是該數(shù)據(jù)結(jié)構(gòu)的定義。
程序清單L6.1ECB數(shù)據(jù)結(jié)構(gòu)
typedefSTruct{
void*OSEventPtr;/*指向消息或者消息隊列的指針*/
INT8UOSEventTbl[OS_EVENT_TBL_SIZE];/*等待任務(wù)列表*/
INT16UOSEventCnt;/*計數(shù)器(當(dāng)事件是信號量時)*/
INT8UOSEventType;/*時間類型*/
INT8UOSEventGrp;/*等待任務(wù)所在的組*/
}OS_EVENT;
.OSEventPtr指針,只有在所定義的事件是郵箱或者消息隊列時才使用。 當(dāng)所定義的事件是郵箱時,它指向一個消息,而當(dāng)所定義的事件是消息隊列時,它指向一個數(shù)據(jù)結(jié)構(gòu),詳見6.06節(jié)消息郵箱和6.07節(jié)消息隊列。
.OSEventTbl[] 和 .OSEventGrp 很像前面講到的OSRdyTbl[]和OSRdyGrp,只不過前兩者包含的是等待某事件的任務(wù),而后兩者包含的是系統(tǒng)中處于就緒狀態(tài)的任務(wù)。(見3.04節(jié)就緒表)
.OSEventCnt 當(dāng)事件是一個信號量時,.OSEventCnt是用于信號量的計數(shù)器,(見6.05節(jié)信號量)。
.OSEventType 定義了事件的具體類型。它可以是信號量(OS_EVENT_SEM)、郵箱
(OS_EVENT_TYPE_MBOX)或消息隊列(OS_EVENT_TYPE_Q)中的一種。用戶要根據(jù)該域的具體值
來調(diào)用相應(yīng)的系統(tǒng)函數(shù),以保證對其進行的操作的正確性。
每個等待事件發(fā)生的任務(wù)都被加入到該事件事件控制塊中的等待任務(wù)列表中,該列表包括.OSEventGrp和.OSEventTbl[]兩個域。變量前面的[.]說明該變量是數(shù)據(jù)結(jié)構(gòu)的一個域。在這
里,所有的任務(wù)的優(yōu)先級被分成8組(每組8個優(yōu)先級),分別對應(yīng).OSEventGrp中的8位。當(dāng)
某組中有任務(wù)處于等待該事件的狀態(tài)時,.OSEventGrp中對應(yīng)的位就被置位。相應(yīng)地,該任務(wù)
在.OSEventTbl[]中的對應(yīng)位也被置位。.OSEventTbl[]數(shù)組的大小由系統(tǒng)中任務(wù)的最低優(yōu)先級
決定,這個值由uCOS_II.H中的OS_LOWEST_PRIO常數(shù)定義。這樣,在任務(wù)優(yōu)先級比較少的情況
下,減少μC/OS-II對系統(tǒng)RAM的占用量。
當(dāng)一個事件發(fā)生后,該事件的等待事件列表中優(yōu)先級最高的任務(wù),也即在.OSEventTbl[]中,所有被置1的位中,優(yōu)先級代碼最小的任務(wù)得到該事件。圖F6.2給出
了.OSEventGrp和.OSEventTbl[]之間的對應(yīng)關(guān)系。該關(guān)系可以描述為:
當(dāng).OSEventTbl[0]中的任何一位為1時,.OSEventGrp中的第0位為1。
當(dāng).OSEventTbl[1]中的任何一位為1時,.OSEventGrp中的第1位為1。
當(dāng).OSEventTbl[2]中的任何一位為1時,.OSEventGrp中的第2位為1。
當(dāng).OSEventTbl[3]中的任何一位為1時,.OSEventGrp中的第3位為1。
當(dāng).OSEventTbl[4]中的任何一位為1時,.OSEventGrp中的第4位為1。
當(dāng).OSEventTbl[5]中的任何一位為1時,.OSEventGrp中的第5位為1。
當(dāng).OSEventTbl[6]中的任何一位為1時,.OSEventGrp中的第6位為1。
當(dāng).OSEventTbl[7]中的任何一位為1時,.OSEventGrp中的第7位為1。
圖F6.2事件的等待任務(wù)列表
下面的代碼將一個任務(wù)放到事件的等待任務(wù)列表中。
程序清單L6.2——將一個任務(wù)插入到事件的等待任務(wù)列表中
pevent->OSEventGrp|=OSMapTbl[prio>>3];
pevent->OSEventTbl[prio>>3]|=OSMapTbl[prio0x07];
其中,prio是任務(wù)的優(yōu)先級,pevent是指向事件控制塊的指針。
從程序清單L6.2可以看出,插入一個任務(wù)到等待任務(wù)列表中所花的時間是相同的,和表中現(xiàn)有多少個任務(wù)無關(guān)。從圖F6.2中可以看出該算法的原理:任務(wù)優(yōu)先級的最低3位決定了該任務(wù)在相應(yīng)的.OSEventTbl[]中的位置,緊接著的3位則決定了該任務(wù)優(yōu)先級在.OSEventTbl[]中的字節(jié)索引。該算法中用到的查找表OSMapTbl[](定義在OS_CORE.C中)一般在ROM中實現(xiàn)。
評論