μC/OS-II的任務(wù)之間的通訊與同步
表T6.1OSMapTbl[]

從等待任務(wù)列表中刪除一個任務(wù)的算法則正好相反,如程序清單L6.3所示。
程序清單L6.3從等待任務(wù)列表中刪除一個任務(wù)
if((pevent->OSEventTbl[prio>>3]=~OSMapTbl[prio0x07])==0){
pevent->OSEventGrp=~OSMapTbl[prio>>3];
}
該代碼清除了任務(wù)在.OSEventTbl[]中的相應(yīng)位,并且,如果其所在的組中不再有處于等待該事件的任務(wù)時(即.OSEventTbl[prio>>3]為0),將.OSEventGrp中的相應(yīng)位也清除了。和上面的由任務(wù)優(yōu)先級確定該任務(wù)在等待表中的位置的算法類似,從等待任務(wù)列表中查找處于等待狀態(tài)的最高優(yōu)先級任務(wù)的算法,也不是從.OSEventTbl[0]開始逐個查詢,而是采用了查找另一個表OSUnMapTbl[256](見文件OS_CORE.C)。這里,用于索引的8位分別代表對應(yīng)的8組中有任務(wù)處于等待狀態(tài),其中的最低位具有最高的優(yōu)先級。用這個值索引,首先得到最高優(yōu)先級任務(wù)所在的組的位置(0~7之間的一個數(shù))。然后利用.OSEventTbl[]中對應(yīng)字節(jié)再在OSUnMapTbl[]中查找,就可以得到最高優(yōu)先級任務(wù)在組中的位置(也是0~7之間的一個數(shù))。
這樣,最終就可以得到處于等待該事件狀態(tài)的最高優(yōu)先級任務(wù)了。程序清單L6.4是該算法的具體實現(xiàn)代碼。
程序清單L6.4在等待任務(wù)列表中查找最高優(yōu)先級的任務(wù)
y=OSUnMapTbl[pevent->OSEventGrp];
x=OSUnMapTbl[pevent->OSEventTbl[y]];
prio=(y3)+x;
舉例來說,如果.OSEventGrp的值是01101000(二進制),而對應(yīng)的OSUnMapTbl[.OSEventGrp]值為3,說明最高優(yōu)先級任務(wù)所在的組是3。類似地,如果.OSEventTbl[3]的值是11100100(二進制),OSUnMapTbl[.OSEventTbl[3]]的值為2,則處于等待狀態(tài)的任務(wù)的最高優(yōu)先級是3×8+2=26。
在μC/OS-II中,事件控制塊的總數(shù)由用戶所需要的信號量、郵箱和消息隊列的總數(shù)決定。
該值由OS_CFG.H中的#defineOS_MAX_EVENTS定義。 在調(diào)用OSInit()時 (見3.11節(jié), μC/OS-II
的初始化),所有事件控制塊被鏈接成一個單向鏈表——空閑事件控制塊鏈表(圖F6.3)。每
當建立一個信號量、郵箱或者消息隊列時,就從該鏈表中取出一個空閑事件控制塊,并對它進
行初始化。因為信號量、郵箱和消息隊列一旦建立就不能刪除,所以事件控制塊也不能放回到
空閑事件控制塊鏈表中。

圖F6.3空閑事件控制塊鏈表——Figure6.3
對于事件控制塊進行的一些通用操作包括:
y 初始化一個事件控制塊
y 使一個任務(wù)進入就緒態(tài)
y 使一個任務(wù)進入等待該事件的狀態(tài)
y 因為等待超時而使一個任務(wù)進入就緒態(tài)
為了避免代碼重復(fù)和減短程代碼長度,μC/OS-II將上面的操作用4個系統(tǒng)函數(shù)實現(xiàn),它們是:OSEventWaitListInit(),OSEventTaskRdy(),OSEventWait()和OSEventTO()。
6.2 初始化一個事件控制塊,OSEventWaitListInit()
程序清單L6.5是函數(shù)OSEventWaitListInit()的源代碼。當建立一個信號量、郵箱或者消息隊列時,相應(yīng)的建立函數(shù)OSSemInit(),OSMboxCreate(),或者OSQCreate()通過調(diào)用
OSEventWaitListInit()對事件控制塊中的等待任務(wù)列表進行初始化。該函數(shù)初始化一個空的等
待任務(wù)列表,其中沒有任何任務(wù)。該函數(shù)的調(diào)用參數(shù)只有一個,就是指向需要初始化的事件控
制塊的指針pevent。
程序清單L6.5初始化ECB塊的等待任務(wù)列表
voidOSEventWaitListInit(OS_EVENT*pevent)
{
INT8Ui;
pevent->OSEventGrp=0x00;
for(i=0;i
pevent->OSEventTbl[i]=0x00;
}
}
6.3 使一個任務(wù)進入就緒態(tài),OSEventTaskRdy()
程序清單L6.6是函數(shù)OSEventTaskRdy()的源代碼。當發(fā)生了某個事件,該事件等待任務(wù)列表中的最高優(yōu)先級任務(wù)(HighestPriorityTask–HPT)要置于就緒態(tài)時,該事件對應(yīng)的OSSemPost(),OSMboxPost(),OSQPost(),和OSQPostFront()函數(shù)調(diào)用OSEventTaskRdy()實現(xiàn)該操作。換句話說,該函數(shù)從等待任務(wù)隊列中刪除HPT任務(wù)(HighestPriorityTask),并把該任務(wù)置于就緒態(tài)。圖F6.4給出了OSEventTaskRdy()函數(shù)最開始的4個動作。
該函數(shù)首先計算HPT任務(wù)在.OSEventTbl[]中的字節(jié)索引[L6.6/F6.4(1)],其結(jié)果是一個從0到OS_LOWEST_PRIO/8+1之間的數(shù),并利用該索引得到該優(yōu)先級任務(wù)在.OSEventGrp中的位屏蔽碼[L6.6/F6.4(2)](從表T6.1可以得到該值)。然后,OSEventTaskRdy()函數(shù)判斷HPT任務(wù)在.OSEventTbl[]中相應(yīng)位的位置[L6.6/F6.4(3)], 其結(jié)果是一個從0到OS_LOWEST_PRIO/8+1
之間的數(shù),以及相應(yīng)的位屏蔽碼[L6.6/F6.4(4)]。根據(jù)以上結(jié)果,OSEventTaskRdy()函數(shù)計算
出HPT任務(wù)的優(yōu)先級[L6.6(5)],然后就可以從等待任務(wù)列表中刪除該任務(wù)了[L6.6(6)]。
任務(wù)的任務(wù)控制塊中包含有需要改變的信息。知道了HPT任務(wù)的優(yōu)先級,就可以得到指向該任務(wù)的任務(wù)控制塊的指針[L6.6(7)]。因為最高優(yōu)先級任務(wù)運行條件已經(jīng)得到滿足,必須停止OSTimeTick()函數(shù)對.OSTCBDly域的遞減操作,所以O(shè)SEventTaskRdy()直接將該域清澈0[L6.6(8)]。因為該任務(wù)不再等待該事件的發(fā)生,所以O(shè)SEventTaskRdy()函數(shù)將其任務(wù)控制塊中指向事件控制塊的指針指向NULL[L6.6(9)]。如果OSEventTaskRdy()是由OSMboxPost()或者OSQPost()調(diào)用的,該函數(shù)還要將相應(yīng)的消息傳遞給HPT,放在它的任務(wù)控制塊中[L6.6(10)]。
另外,當OSEventTaskRdy()被調(diào)用時,位屏蔽碼msk作為參數(shù)傳遞給它。該參數(shù)是用于對任務(wù)控制塊中的位清零的位屏蔽碼,和所發(fā)生事件的類型相對應(yīng)[L6.6(11)]。最后,根據(jù).OSTCBStat判斷該任務(wù)是否已處于就緒狀態(tài)[L6.6(12)]。如果是,則將HPT插入到μC/OS-II的就緒任務(wù)列表中[L6.6(13)]。注意,HPT任務(wù)得到該事件后不一定進入就緒狀態(tài),也許該任務(wù)已經(jīng)由于其它
評論