μC/OS-II的任務之間的通訊與同步
在μC/OS-II中,有多種方法可以保護任務之間的共享數據和提供任務之間的通訊。在前面的章節中,已經講到了其中的兩種:
本文引用地址:http://cqxgywz.com/article/201610/305741.htm一是利用宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()來關閉中斷和打開中斷。當兩個任務或者一個任務和一個中斷服務子程序共享某些數據時,可以采用這種方法,詳見3.00節臨界段、8.03.02節 OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL()及9.03.02節臨界段,OS_CPU.H;
二是利用函數OSSchedLock()和OSSchekUnlock()對μC/OS-II中的任務調度函數上鎖和開鎖。用這種方法也可以實現數據的共享,詳見3.06節 給調度器上鎖和開鎖。
本章將介紹另外三種用于數據共享和任務通訊的方法:信號量、郵箱和消息隊列。
圖F6.1介紹了任務和中斷服務子程序之間是如何進行通訊的。
一個任務或者中斷服務子程序可以通過事件控制塊ECB(EventCONtrolBlocks)來向另外的任務發信號[F6.1A(1)]。這里,所有的信號都被看成是事件(Event)。這也說明為什么上面把用于通訊的數據結構叫做事件控制塊。一個任務還可以等待另一個任務或中斷服務子程序給它發送信號[F6.1A(2)]。這里要注意的是,只有任務可以等待事件發生,中斷服務子程序是不能這樣做的。對于處于等待狀態的任務,還可以給它指定一個最長等待時間,以此來防止因為等待的事件沒有發生而無限期地等下去。
多個任務可以同時等待同一個事件的發生[F6.1B]。在這種情況下,當該事件發生后,所有等待該事件的任務中,優先級最高的任務得到了該事件并進入就緒狀態,準備執行。上面講到的事件,可以是信號量、郵箱或者消息隊列等。當事件控制塊是一個信號量時,任務可以等待它,也可以給它發送消息。

圖6.1事件控制塊的使用
6.1 事件控制塊ECB
μC/OS-II通過uCOS_II.H中定義的OS_EVENT數據結構來維護一個事件控制塊的所有信息[程序清單L6.1],也就是本章開篇講到的事件控制塊ECB。該結構中除了包含了事件本身的定義,如用于信號量的計數器,用于指向郵箱的指針,以及指向消息隊列的指針數組等,還定義了等待該事件的所有任務的列表。程序清單L6.1是該數據結構的定義。
程序清單L6.1ECB數據結構
typedefSTruct{
void*OSEventPtr;/*指向消息或者消息隊列的指針*/
INT8UOSEventTbl[OS_EVENT_TBL_SIZE];/*等待任務列表*/
INT16UOSEventCnt;/*計數器(當事件是信號量時)*/
INT8UOSEventType;/*時間類型*/
INT8UOSEventGrp;/*等待任務所在的組*/
}OS_EVENT;
.OSEventPtr指針,只有在所定義的事件是郵箱或者消息隊列時才使用。 當所定義的事件是郵箱時,它指向一個消息,而當所定義的事件是消息隊列時,它指向一個數據結構,詳見6.06節消息郵箱和6.07節消息隊列。
.OSEventTbl[] 和 .OSEventGrp 很像前面講到的OSRdyTbl[]和OSRdyGrp,只不過前兩者包含的是等待某事件的任務,而后兩者包含的是系統中處于就緒狀態的任務。(見3.04節就緒表)
.OSEventCnt 當事件是一個信號量時,.OSEventCnt是用于信號量的計數器,(見6.05節信號量)。
.OSEventType 定義了事件的具體類型。它可以是信號量(OS_EVENT_SEM)、郵箱
(OS_EVENT_TYPE_MBOX)或消息隊列(OS_EVENT_TYPE_Q)中的一種。用戶要根據該域的具體值
來調用相應的系統函數,以保證對其進行的操作的正確性。
每個等待事件發生的任務都被加入到該事件事件控制塊中的等待任務列表中,該列表包括.OSEventGrp和.OSEventTbl[]兩個域。變量前面的[.]說明該變量是數據結構的一個域。在這
里,所有的任務的優先級被分成8組(每組8個優先級),分別對應.OSEventGrp中的8位。當
某組中有任務處于等待該事件的狀態時,.OSEventGrp中對應的位就被置位。相應地,該任務
在.OSEventTbl[]中的對應位也被置位。.OSEventTbl[]數組的大小由系統中任務的最低優先級
決定,這個值由uCOS_II.H中的OS_LOWEST_PRIO常數定義。這樣,在任務優先級比較少的情況
下,減少μC/OS-II對系統RAM的占用量。
當一個事件發生后,該事件的等待事件列表中優先級最高的任務,也即在.OSEventTbl[]中,所有被置1的位中,優先級代碼最小的任務得到該事件。圖F6.2給出
了.OSEventGrp和.OSEventTbl[]之間的對應關系。該關系可以描述為:
當.OSEventTbl[0]中的任何一位為1時,.OSEventGrp中的第0位為1。
當.OSEventTbl[1]中的任何一位為1時,.OSEventGrp中的第1位為1。
當.OSEventTbl[2]中的任何一位為1時,.OSEventGrp中的第2位為1。
當.OSEventTbl[3]中的任何一位為1時,.OSEventGrp中的第3位為1。
當.OSEventTbl[4]中的任何一位為1時,.OSEventGrp中的第4位為1。
當.OSEventTbl[5]中的任何一位為1時,.OSEventGrp中的第5位為1。
當.OSEventTbl[6]中的任何一位為1時,.OSEventGrp中的第6位為1。
當.OSEventTbl[7]中的任何一位為1時,.OSEventGrp中的第7位為1。

圖F6.2事件的等待任務列表
下面的代碼將一個任務放到事件的等待任務列表中。
程序清單L6.2——將一個任務插入到事件的等待任務列表中
pevent->OSEventGrp|=OSMapTbl[prio>>3];
pevent->OSEventTbl[prio>>3]|=OSMapTbl[prio0x07];
其中,prio是任務的優先級,pevent是指向事件控制塊的指針。
從程序清單L6.2可以看出,插入一個任務到等待任務列表中所花的時間是相同的,和表中現有多少個任務無關。從圖F6.2中可以看出該算法的原理:任務優先級的最低3位決定了該任務在相應的.OSEventTbl[]中的位置,緊接著的3位則決定了該任務優先級在.OSEventTbl[]中的字節索引。該算法中用到的查找表OSMapTbl[](定義在OS_CORE.C中)一般在ROM中實現。












評論