新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μC/OS-II的任务之间的通讯与同步

μC/OS-II的任务之间的通讯与同步

作者: 时间:2016-10-08 来源:网络 收藏

制块的.OSEventGrp域为非0值时,说明该消息队列的等待任务列表中有任务。这时,调用

OSEventTaskRdy()函数[见6.02节,使一个任务进入就绪状态,OSEventTaskRdy()]从列表中取出最高优先级的任务[L6.23(3)], 并将它置于就绪状态。 然后调用函数OSSched()[L6.23(4)]进行任务的调度。如果上面取出的任务的优先级在整个系统就绪的任务里也是最高的,而且OSQPost()函数不是中断服务子程序调用的,就执行任务切换,该最高优先级任务被执行。否则的话,OSSched()函数直接返回,调用 OSQPost()函数的任务继续执行。

程序清单L6.23向消息队列发送一条消息

INT8UOSQPost(OS_EVENT*pevent,void*msg)

{

OS_Q*pq;

OS_ENTER_CRITICAL();

if(pevent->OSEventType!=OS_EVENT_TYPE_Q){(1)

OS_EXIT_CRITICAL();

return(OS_ERR_EVENT_TYPE);

}

if(pevent->OSEventGrp){(2)

OSEventTaskRdy(pevent,msg,OS_STAT_Q);(3)

OS_EXIT_CRITICAL();

OSSched();

(4)

return(OS_NO_ERR);

}else{

pq=pevent->OSEventPtr;

if(pq->OSQEntries>=pq->OSQSize){(5)

OS_EXIT_CRITICAL();

return(OS_Q_FULL);

}else{

*pq->OSQIn++=msg;(6)

pq->OSQEntries++;

if(pq->OSQIn==pq->OSQEnd){

pq->OSQIn=pq->OSQStart;

}

OS_EXIT_CRITICAL();

}

return(OS_NO_ERR);

}

}

如果没有任务等待该消息队列中的消息,而且此时消息队列未满[L6.23(5)],指向该消息的指针被插入到消息队列中[L6.23(6)]。这样,下一个调用OSQPend()函数的任务就可以马上得到该消息。注意,如果此时消息队列已满,那么该消息将由于不能插入到消息队列中而丢失。

此外,如果OSQPost()函数是由中断服务子程序调用的,那么即使产生了更高优先级的任务,也不会在调用OSSched()函数时发生任务切换。这个动作一直要等到中断嵌套的最外层中断服务子程序调用OSIntExit()函数时才能进行(见3.09节,μC/OS-II中的中断)。

6.8.4 向消息队列发送一个消息(后进先出LIFO),OSQPostFront()

OSQPostFront()函数和OSQPost()基本上是一样的, 只是在插入新的消息到消息队列中时,使用.OSQOut作为指向下一个插入消息的单元的指针,而不是.OSQIn。程序清单L6.24是它的源代码。值得注意的是,.OSQOut指针指向的是已经插入了消息指针的单元,所以再插入新的消

息指针前,必须先将.OSQOut指针在消息队列中前移一个单元。如果.OSQOut指针指向的当前单

元是队列中的第一个单元[L6.24(1)],这时再前移就会发生越界,需要特别地将该指针指向队

列的末尾[L6.24(2)]。由于.OSQEnd指向的是消息队列中最后一个单元的下一个单元,因此.OSQOut必须被调整到指向队列的有效范围内[L6.24(3)]。因为QSQPend()函数取出的消息是

由OSQPend()函数刚刚插入的,因此OSQPostFront()函数实现了一个LIFO队列。

程序清单L6.24向消息队列发送一条消息(LIFO)

INT8UOSQPostFront(OS_EVENT*pevent,void*msg)

{

OS_Q*pq;

OS_ENTER_CRITICAL();

if(pevent->OSEventType!=OS_EVENT_TYPE_Q){

OS_EXIT_CRITICAL();

return(OS_ERR_EVENT_TYPE);

}

if(pevent->OSEventGrp){

OSEventTaskRdy(pevent,msg,OS_STAT_Q);

OS_EXIT_CRITICAL();

OSSched();

return(OS_NO_ERR);

}else{

pq=pevent->OSEventPtr;

if(pq->OSQEntries>=pq->OSQSize){

OS_EXIT_CRITICAL();

return(OS_Q_FULL);

}else{

if(pq->OSQOut==pq->OSQStart){(1)

pq->OSQOut=pq->OSQEnd;(2)

}

pq->OSQOut--;(3)

*pq->OSQOut=msg;

pq->OSQEntries++;

OS_EXIT_CRITICAL();

}

return(OS_NO_ERR);

}

}

6.8.5 无等待地从一个消息队列中取得消息,OSQAccept()

如果试图从消息队列中取出一条消息,而此时消息队列又为空时,也可以不让调用任务等待而直接返回调用函数。这个操作可以调用OSQAccept()函数来完成。程序清单L6.25是该函数的源代码。 OSQAccept()函数首先查看pevent指向的事件控制块是否是由OSQCreate()函数建立的[L6.25(1)],然后它检查当前消息队列中是否有消息[L6.25(2)]。如果消息队列中有至少一条消息,那么就从.OSQOut指向的单元中取出消息[L6.25(3)]。OSQAccept()函数的调用函数需要对OSQAccept()返回的指针进行检查。如果该指针是NULL值,说明消息队列是空的,其中没有消息可以[L6.25(4)]。否则的话,说明已经从消息队列中成功地取得了一条消息。当中断服务子程序要从消息队列中取消息时, 必须使用OSQAccept()函数, 而不能使用OSQPend()函数。

程序清单L6.25无等待地从消息队列中取一条消息

void*OSQAccept(OS_EVENT*pevent)

{

void*msg;

OS_Q*pq;

OS_ENTER_CRITICAL();

if(pevent->OSEventType!=OS_EVENT_TYPE_Q){(1)

OS_EXIT_CRITICAL();

return((void*)0);

}

pq=pevent->OSEventPtr;

if(pq->OSQEntries!=0){(2)

msg=*pq->OSQOut++;(3)

pq->OSQEntries--;

if(pq->OSQOut==pq->OSQEnd){

pq->OSQOut=pq->OSQStart;

}

}else{

msg=(void*)0;(4)

}

OS_EXIT_CRITICAL();

return(msg);

}

6.8.6 清空一个消息队列,OSQFlush()

OSQFlush()函数允许用户删除一个消息队列中的所有消息,重新开始使用。程序清单L6.26是该函数的源代码。和前面的其它函数一样,该函数首先检查pevent指针是否是执行一个消息队列[L6.26(1)],然后将队列的插入指针和取出指针复位,使它们都指向队列起始单元,同时,将队列中的消息数设为0[L6.26(2)]。这里,没有检查该消息队列的等待任务列表是否为空,因为只要该等待任务列表不空,.OSQEntries就一定是0。唯一不同的是,指针.OSQIn和.OSQOut此时可以指向消息队列中的任何单元,不一定是起始单元。



关键词:

评论


相关推荐

技术专区

关闭