μC/OS-II的任務(wù)之間的通訊與同步
另外,消息隊列一旦建立就不能再刪除了。試想,如果有任務(wù)正在等待某個消息隊列中的消息,而此時又刪除該消息隊列,將是很危險的。
程序清單L6.21建立一個消息隊列
OS_EVENT*OSQCreate(void**start,INT16Usize)
{
OS_EVENT*pevent;
OS_Q*pq;
OS_ENTER_CRITICAL();
pevent=OSEventFreeList;(1)
if(OSEventFreeList!=(OS_EVENT*)0){
OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr;(2)
}
OS_EXIT_CRITICAL();
if(pevent!=(OS_EVENT*)0){
OS_ENTER_CRITICAL();
pq=OSQFreeList;(3)
if(OSQFreeList!=(OS_Q*)0){
OSQFreeList=OSQFreeList->OSQPtr;
}
OS_EXIT_CRITICAL();
if(pq!=(OS_Q*)0){
pq->OSQStart=start;(4)
pq->OSQEnd=start[size];
pq->OSQIn=start;
pq->OSQOut=start;
pq->OSQSize=size;
pq->OSQEntries=0;
pevent->OSEventType=OS_EVENT_TYPE_Q;(5)
pevent->OSEventPtr=pq;(6)
OSEventWaitListInit(pevent);(7)
}else{
OS_ENTER_CRITICAL();
pevent->OSEventPtr=(void*)OSEventFreeList;(8)
OSEventFreeList=pevent;
OS_EXIT_CRITICAL();
pevent=(OS_EVENT*)0;
}
}
return(pevent);(9)
}
6.8.2 等待一個消息隊列中的消息,OSQPend()
程序清單L6.22是OSQPend()函數(shù)的源代碼。OSQPend()函數(shù)首先檢查事件控制塊是否是由OSQCreate()函數(shù)建立的[L6.22(1)],接著,該函數(shù)檢查消息隊列中是否有消息可用(即.OSQEntries是否大于0) [L6.22(2)]。 如果有, OSQPend()函數(shù)將指向消息的指針復(fù)制到msg變量中, 并讓.OSQOut指針指向隊列中的下一個單元[L6.22(3)],然后將隊列中的有效消息數(shù)減1[L6.22(4)]。因為消息隊列是一個循環(huán)的緩沖區(qū),OSQPend()函數(shù)需要檢查.OSQOut是否超過了
隊列中的最后一個單元[L6.22(5)]。當(dāng)發(fā)生這種越界時,就要將.OSQOut重新調(diào)整到指向隊列的起始單元[L6.22(6)]。這是我們調(diào)用OSQPend()函數(shù)時所期望的,也是執(zhí)行OSQPend()函數(shù)最快的路徑。
程序清單L6.22在一個消息隊列中等待一條消息
void*OSQPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err)
{
void*msg;
OS_Q*pq;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_Q){(1)
OS_EXIT_CRITICAL();
*err=OS_ERR_EVENT_TYPE;
return((void*)0);
}
pq=pevent->OSEventPtr;
if(pq->OSQEntries!=0){(2)
msg=*pq->OSQOut++;(3)
pq->OSQEntries--;(4)
if(pq->OSQOut==pq->OSQEnd){(5)
pq->OSQOut=pq->OSQStart;(6)
}
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}elseif(OSIntNesting>0){(7)
OS_EXIT_CRITICAL();
*err=OS_ERR_PEND_ISR;
}else{
OSTCBCur->OSTCBStat|=OS_STAT_Q;(8)
OSTCBCur->OSTCBDly=timeout;
OSEventTaskWait(pevent);
OS_EXIT_CRITICAL();
OSSched();(9)
OS_ENTER_CRITICAL();
if((msg=OSTCBCur->OSTCBMsg)!=(void*)0){(10)
OSTCBCur->OSTCBMsg=(void*)0;
OSTCBCur->OSTCBStat=OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;(11)
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}elseif(OSTCBCur->OSTCBStatOS_STAT_Q){(12)
OSEventTO(pevent);(13)
OS_EXIT_CRITICAL();
msg=(void*)0;(14)
*err=OS_TIMEOUT;
}else{
msg=*pq->OSQOut++;(15)
pq->OSQEntries--;
if(pq->OSQOut==pq->OSQEnd){
pq->OSQOut=pq->OSQStart;
}
OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;(16)
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}
}
return(msg);(17)
}
如果這時消息隊列中沒有消息(.OSEventEntries是0),OSQPend()函數(shù)檢查它的調(diào)用者是否是中斷服務(wù)子程序[L6.22(7)]。象OSSemPend()和OSMboxPend()函數(shù)一樣,不能在中斷服務(wù)子程序中調(diào)用OSQPend(), 因為中斷服務(wù)子程序是不能等待的。 但是, 如果消息隊列中有消息,即使從中斷服務(wù)子程序中調(diào)用OSQPend()函數(shù),也一樣是成功的。
如果消息隊列中沒有消息,調(diào)用OSQPend()函數(shù)的任務(wù)被掛起[L6.22(8)]。當(dāng)有其它的任
務(wù)向該消息隊列發(fā)送了消息或者等待時間超時,并且該任務(wù)成為最高優(yōu)先級任務(wù)時,OSSched()
返回[L6.22(9)]。這時,OSQPend()要檢查是否有消息被放到該任務(wù)的任務(wù)控制塊中[L6.22(10)]。如果有,那么該次函數(shù)調(diào)用成功,把任務(wù)的任務(wù)控制塊中指向消息隊列的指針刪除[L6.22(17)],并將對應(yīng)的消息被返回到調(diào)用函數(shù)[L6.22(17)]。
在OSQPend()函數(shù)中,通過檢查任務(wù)的任務(wù)控制塊中的.OSTCBStat域,可以知道是否等到時間超時。如果其對應(yīng)的OS_STAT_Q位被置1,說明任務(wù)等待已經(jīng)超時[L6.22(12)]。這時,通過調(diào)用函數(shù)OSEventTo()可以將任務(wù)從消息隊列的等待任務(wù)列表中刪除[L6.22(13)]。這時,因為消息隊列中沒有消息,所以返回的指針是NULL[L6.22(14)]。
如果任務(wù)控制塊標(biāo)志位中的OS_STAT_Q位沒有被置1,說明有任務(wù)發(fā)出了一條消息。
OSQPend()函數(shù)從隊列中取出該消息[L6.22(15)]。然后,將任務(wù)的任務(wù)控制中指向事件控制塊的指針刪除[L6.22(16)]。
6.8.3 向消息隊列發(fā)送一個消息(FIFO),OSQPost()
程序清單L6.23是OSQPost()函數(shù)的源代碼。在確認(rèn)事件控制塊是消息隊列后
[L6.23(1)],OSQPost()函數(shù)檢查是否有任務(wù)在等待該消息隊列中的消息[L6.23(2)]。當(dāng)事件控
評論