新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μ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)]。因为消息队列是一个循环的缓冲区,OSQPend()函数需要检查.OSQOut是否超过了

队列中的最后一个单元[L6.22(5)]。当发生这种越界时,就要将.OSQOut重新调整到指向队列的起始单元[L6.22(6)]。这是我们调用OSQPend()函数时所期望的,也是执行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)]。当有其它的任

务向该消息队列发送了消息或者等待时间超时,并且该任务成为最高优先级任务时,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,说明有任务发出了一条消息。

OSQPend()函数从队列中取出该消息[L6.22(15)]。然后,将任务的任务控制中指向事件控制块的指针删除[L6.22(16)]。

6.8.3 向消息队列发送一个消息(FIFO),OSQPost()

程序清单L6.23是OSQPost()函数的源代码。在确认事件控制块是消息队列后

[L6.23(1)],OSQPost()函数检查是否有任务在等待该消息队列中的消息[L6.23(2)]。当事件控



关键词:

评论


相关推荐

技术专区

关闭