新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > μC/OS-II的任務之間的通訊與同步

μC/OS-II的任務之間的通訊與同步

作者: 時間:2016-10-08 來源:網絡 收藏

另外,消息隊列一旦建立就不能再刪除了。試想,如果有任務正在等待某個消息隊列中的消息,而此時又刪除該消息隊列,將是很危險的。

程序清單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()函數的源代碼。OSQPend()函數首先檢查事件控制塊是否是由OSQCreate()函數建立的[L6.22(1)],接著,該函數檢查消息隊列中是否有消息可用(即.OSQEntries是否大于0) [L6.22(2)]。 如果有, OSQPend()函數將指向消息的指針復制到msg變量中, 并讓.OSQOut指針指向隊列中的下一個單元[L6.22(3)],然后將隊列中的有效消息數減1[L6.22(4)]。因為消息隊列是一個循環(huán)的緩沖區(qū),OSQPend()函數需要檢查.OSQOut是否超過了

隊列中的最后一個單元[L6.22(5)]。當發(fā)生這種越界時,就要將.OSQOut重新調整到指向隊列的起始單元[L6.22(6)]。這是我們調用OSQPend()函數時所期望的,也是執(zhí)行OSQPend()函數最快的路徑。

程序清單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()函數檢查它的調用者是否是中斷服務子程序[L6.22(7)]。象OSSemPend()和OSMboxPend()函數一樣,不能在中斷服務子程序中調用OSQPend(), 因為中斷服務子程序是不能等待的。 但是, 如果消息隊列中有消息,即使從中斷服務子程序中調用OSQPend()函數,也一樣是成功的。

如果消息隊列中沒有消息,調用OSQPend()函數的任務被掛起[L6.22(8)]。當有其它的任

務向該消息隊列發(fā)送了消息或者等待時間超時,并且該任務成為最高優(yōu)先級任務時,OSSched()

返回[L6.22(9)]。這時,OSQPend()要檢查是否有消息被放到該任務的任務控制塊中[L6.22(10)]。如果有,那么該次函數調用成功,把任務的任務控制塊中指向消息隊列的指針刪除[L6.22(17)],并將對應的消息被返回到調用函數[L6.22(17)]。

在OSQPend()函數中,通過檢查任務的任務控制塊中的.OSTCBStat域,可以知道是否等到時間超時。如果其對應的OS_STAT_Q位被置1,說明任務等待已經超時[L6.22(12)]。這時,通過調用函數OSEventTo()可以將任務從消息隊列的等待任務列表中刪除[L6.22(13)]。這時,因為消息隊列中沒有消息,所以返回的指針是NULL[L6.22(14)]。

如果任務控制塊標志位中的OS_STAT_Q位沒有被置1,說明有任務發(fā)出了一條消息。

OSQPend()函數從隊列中取出該消息[L6.22(15)]。然后,將任務的任務控制中指向事件控制塊的指針刪除[L6.22(16)]。

6.8.3 向消息隊列發(fā)送一個消息(FIFO),OSQPost()

程序清單L6.23是OSQPost()函數的源代碼。在確認事件控制塊是消息隊列后

[L6.23(1)],OSQPost()函數檢查是否有任務在等待該消息隊列中的消息[L6.23(2)]。當事件控



關鍵詞:

評論


相關推薦

技術專區(qū)

關閉