μC/OS-II的任務(wù)之間的通訊與同步
值得注意的是,在μC/OS-II中,信號(hào)量一旦建立就不能刪除了,因此也就不可能將一個(gè)已分配的任務(wù)控制塊再放回到空閑ECB鏈表中。如果有任務(wù)正在等待某個(gè)信號(hào)量,或者某任務(wù)的運(yùn)行依賴于某信號(hào)量的出現(xiàn)時(shí),刪除該任務(wù)是很危險(xiǎn)的。
程序清單L6.9建立一個(gè)信號(hào)量
OS_EVENT*OSSemCreate(INT16Ucnt)
{
OS_EVENT*pevent;
OS_ENTER_CRITICAL();
pevent=OSEventFreeList;(1)
if(OSEventFreeList!=(OS_EVENT*)0){(2)
OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if(pevent!=(OS_EVENT*)0){(3)
pevent->OSEventType=OS_EVENT_TYPE_SEM;(4)
pevent->OSEventCnt=cnt;(5)
OSEventWaitListInit(pevent);(6)
}
return(pevent);(7)
}
6.6.2 等待一個(gè)信號(hào)量,OSSemPend()
程序清單L6.10是OSSemPend()函數(shù)的源代碼。它首先檢查指針pevent所指的任務(wù)控制塊是否是由OSSemCreate()建立的[L6.10(1)]。如果信號(hào)量當(dāng)前是可用的(信號(hào)量的計(jì)數(shù)值大于0)[L6.10(2)],將信號(hào)量的計(jì)數(shù)值減1[L6.10(3)],然后函數(shù)將“無錯(cuò)”錯(cuò)誤代碼返回給它的調(diào)用函數(shù)。顯然,如果正在等待信號(hào)量,這時(shí)的輸出正是我們所希望的,也是運(yùn)行OSSemPend()函數(shù)最快的路徑。
如果此時(shí)信號(hào)量無效(計(jì)數(shù)器的值是0),OSSemPend()函數(shù)要進(jìn)一步檢查它的調(diào)用函數(shù)是不是中斷服務(wù)子程序[L6.10(4)]。在正常情況下,中斷服務(wù)子程序是不會(huì)調(diào)用OSSemPend()函數(shù)的。這里加入這些代碼,只是為了以防萬一。當(dāng)然,在信號(hào)量有效的情況下,即使是中斷服務(wù)
子程序調(diào)用的OSSemPend(),函數(shù)也會(huì)成功返回,不會(huì)出任何錯(cuò)誤。
如果信號(hào)量的計(jì)數(shù)值為0,而OSSemPend()函數(shù)又不是由中斷服務(wù)子程序調(diào)用的,則調(diào)
用OSSemPend()函數(shù)的任務(wù)要進(jìn)入睡眠狀態(tài),等待另一個(gè)任務(wù)(或者中斷服務(wù)子程序)發(fā)出該信
號(hào)量(見下節(jié))。OSSemPend()允許用戶定義一個(gè)最長(zhǎng)等待時(shí)間作為它的參數(shù),這樣可以避免該
任務(wù)無休止地等待下去。如果該參數(shù)值是一個(gè)大于0的值,那么該任務(wù)將一直等到信號(hào)有效或
者等待超時(shí)。如果該參數(shù)值為0,該任務(wù)將一直等待下去。OSSemPend()函數(shù)通過將任務(wù)控制塊
中的狀態(tài)標(biāo)志.OSTCBStat置1,把任務(wù)置于睡眠狀態(tài)[L6.10(5)],等待時(shí)間也同時(shí)置入任務(wù)控
制塊中[L6.10(6)],該值在OSTimeTick()函數(shù)中被逐次遞減。注意,OSTimeTick()函數(shù)對(duì)每個(gè)
任務(wù)的任務(wù)控制塊的.OSTCBDly域做遞減操作(只要該域不為0)[見3.10節(jié),時(shí)鐘節(jié)拍]。真
正將任務(wù)置入睡眠狀態(tài)的操作在OSEventTaskWait()函數(shù)中執(zhí)行[見6.03節(jié),讓一個(gè)任務(wù)等待
某個(gè)事件,OSEventTaskWait()][L6.10(7)]。
因?yàn)楫?dāng)前任務(wù)已經(jīng)不是就緒態(tài)了,所以任務(wù)調(diào)度函數(shù)將下一個(gè)最高優(yōu)先級(jí)的任務(wù)調(diào)入,準(zhǔn)備運(yùn)行[L6.10(8)]。當(dāng)信號(hào)量有效或者等待時(shí)間到后,調(diào)用OSSemPend()函數(shù)的任務(wù)將再一次成為最高優(yōu)先級(jí)任務(wù)。這時(shí)OSSched()函數(shù)返回。這之后,OSSemPend()要檢查任務(wù)控制塊中的狀態(tài)標(biāo)志,看該任務(wù)是否仍處于等待信號(hào)量的狀態(tài)[L6.10(9)]。如果是,說明該任務(wù)還沒有被OSSemPost()函數(shù)發(fā)出的信號(hào)量喚醒。事實(shí)上,該任務(wù)是因?yàn)榈却瑫r(shí)而由TimeTick()函數(shù)把它置為就緒狀態(tài)的。這種情況下,OSSemPend()函數(shù)調(diào)用 OSEventTO()函數(shù)將任務(wù)從等待任務(wù)列表中刪除[L6.10(10)],并返回給它的調(diào)用任務(wù)一個(gè)“超時(shí)”的錯(cuò)誤代碼。如果任務(wù)的任務(wù)控制塊中的OS_STAT_SEM標(biāo)志位沒有置位,就認(rèn)為調(diào)用 OSSemPend()的任務(wù)已經(jīng)得到了該信號(hào)量,將指向信號(hào)量ECB的指針從該任務(wù)的任務(wù)控制塊中刪除,并返回給調(diào)用函數(shù)一個(gè)“無錯(cuò)”的錯(cuò)誤代碼[L6.10(11)]。
程序清單L6.10等待一個(gè)信號(hào)量
voidOSSemPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err)
{
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_SEM){(1)
OS_EXIT_CRITICAL();
*err=OS_ERR_EVENT_TYPE;
}
if(pevent->OSEventCnt>0){(2)
pevent->OSEventCnt--;(3)
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}elseif(OSIntNesting>0){(4)
OS_EXIT_CRITICAL();
*err=OS_ERR_PEND_ISR;
}else{
OSTCBCur->OSTCBStat|=OS_STAT_SEM;(5)
OSTCBCur->OSTCBDly=timeout;(6)
OSEventTaskWait(pevent);(7)
OS_EXIT_CRITICAL();
OSSched();(8)
OS_ENTER_CRITICAL();
if(OSTCBCur->OSTCBStatOS_STAT_SEM){(9)
OSEventTO(pevent);(10)
OS_EXIT_CRITICAL();
*err=OS_TIMEOUT;
}else{
OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;(11)
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}
}
}
6.6.3 發(fā)送一個(gè)信號(hào)量,OSSemPost()
程序清單L6.11是OSSemPost()函數(shù)的源代碼。它首先檢查參數(shù)指針pevent指向的任務(wù)控制塊是否是OSSemCreate()函數(shù)建立的[L6.11(1)],接著檢查是否有任務(wù)在等待該信號(hào)量[L6.11(2)]。如果該任務(wù)控制塊中的.OSEventGrp域不是0,說明有任務(wù)正在等待該信號(hào)量。這時(shí),就要調(diào)用函數(shù)OSEventTaskRdy()[見6.02節(jié),使一個(gè)任務(wù)進(jìn)入就緒狀態(tài),OSEventTaskRdy()],把其中的最高優(yōu)先級(jí)任務(wù)從等待任務(wù)列表中刪除[L6.11(3)]并使它進(jìn)入就緒狀態(tài)。然后,調(diào)用OSSched()任務(wù)調(diào)度函數(shù)檢查該任務(wù)是否是系統(tǒng)中的最高優(yōu)先級(jí)的就緒任務(wù)[L6.11(4)]。如果是,這時(shí)就要進(jìn)行任務(wù)切換[當(dāng)OSSemPost()函數(shù)是在任務(wù)中調(diào)用的],準(zhǔn)備執(zhí)行該就緒任務(wù)。如果不是,OSSched()直接返回,調(diào)用 OSSemPost()的任務(wù)得以繼續(xù)執(zhí)行。如果這時(shí)沒有任務(wù)在等待該信號(hào)量,該信號(hào)量的計(jì)數(shù)值就簡(jiǎn)單地加1[L6.11(5)]。
上面是由任務(wù)調(diào)用OSSemPost()時(shí)的情況。當(dāng)中斷服務(wù)子程序調(diào)用該函數(shù)時(shí),不會(huì)發(fā)生上面的任務(wù)切換。如果需要,任務(wù)切換要等到中斷嵌套的最外層中斷服務(wù)子程序調(diào)用OSIntExit()函數(shù)后才能進(jìn)行(見3.09節(jié),μC/OS-II中的中斷)。
評(píng)論