μC/OS-II的任务之间的通讯与同步
者还包含了另外两个域
(.OSEventCnt和.OSEventType),而OS_MBOX_DATA只包含邮箱中的消息指针(.OSMsg)和该邮箱现有的等待任务列表(.OSEventTbl[]和.OSEventGrp)。
和前面的所以函数一样,该函数也是先检查事件控制是否是邮箱[L6.18(1)]。然后,将邮箱中的等待任务列表[L6.18(2)]和邮箱中的消息[L6.18(3)]从OS_EVENT数据结构复制到OS_MBOX_DATA数据结构。
程序清单L6.18查询邮箱的状态
INT8UOSMboxQuery(OS_EVENT*pevent,OS_MBOX_DATA*pdata)
{
INT8Ui;
INT8U*psrc;
INT8U*pdest;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_MBOX){(1)
OS_EXIT_CRITICAL();
return(OS_ERR_EVENT_TYPE);
}
pdata->OSEventGrp=pevent->OSEventGrp;(2)
psrc=pevent->OSEventTbl[0];
pdest=pdata->OSEventTbl[0];
for(i=0;i
*pdest++=*psrc++;
}
pdata->OSMsg=pevent->OSEventPtr;(3)
OS_EXIT_CRITICAL();
return(OS_NO_ERR);
}
6.7.6 用邮箱作二值信号量
一个邮箱可以被用作二值的信号量。 首先, 在初始化时, 将邮箱设置为一个非零的指针(如
void*1)。这样,一个任务可以调用OSMboxPend()函数来请求一个信号量,然后通过调用
OSMboxPost()函数来释放一个信号量。程序清单L6.19说明了这个过程是如何工作的。如果用
户只需要二值信号量和邮箱,这样做可以节省代码空间。这时可以将OS_SEM_EN设置为0,只使
用邮箱就可以了。
程序清单L6.19使用邮箱作为二值信号量
OS_EVENT*MboxSem;
voIDTask1(void*pdata)
{
INT8Uerr;
for(;;){
OSMboxPend(MboxSem,0,err);/*获得对资源的访问权*/
.
./*任务获得信号量,对资源进行访问*/
.
OSMboxPost(MboxSem,(void*)1);/*释放对资源的访问权*/
}
}
6.7.7 用邮箱实现延时,而不使用OSTimeDly()
邮箱的等待超时功能可以被用来模仿OSTimeDly()函数的延时,如程序清单L6.20所示。
如果在指定的时间段TIMEOUT内,没有消息到来,Task1()函数将继续执行。这和OSTimeDly(TIMEOUT)功能很相似。但是,如果Task2()在指定的时间结束之前,向该邮箱发送了一个“哑”消息,Task1()就会提前开始继续执行。这和调用OSTimeDlyResume()函数的功能是一样的。注意,这里忽略了对返回的消息的检查,因为此时关心的不是得到了什么样的消息。
程序清单L6.20使用邮箱实现延时
OS_EVENT*MboxTimeDly;
voidTask1(void*pdata)
{
INT8Uerr;
for(;;){
OSMboxPend(MboxTimeDly, TIMEOUT,err);/*延时该任务*/
.
./*延时结束后执行的代码*/
.
}
}
voidTask2(void*pdata)
{
INT8Uerr;
for(;;){
OSMboxPost(MboxTimeDly,(void*)1);/*取消任务1的延时*/
.
.
}
}
6.8 消息队列
消息队列是μC/OS-II中另一种通讯机制, 它可以使一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量。因具体的应用有所不同,每个指针指向的数据结构变量也有所不同。为了使用μC/OS-II的消息队列功能,需要在OS_CFG.H文件中,将OS_Q_EN常数设置为1,并且通过常数OS_MAX_QS来决定μC/OS-II支持的最多消息队列数。
在使用一个消息队列之前, 必须先建立该消息队列。 这可以通过调用OSQCreate()函数 (见
6.07.01节),并定义消息队列中的单元数(消息数)来完成。
μC/OS-II提供了7个对消息队列进行操作的函数:OSQCreate(),OSQPend(),OSQPost(),
OSQPostFront(),OSQAccept(),OSQFlush()和OSQQuery()函数。图F6.7是任务、中断服务子程序和消息队列之间的关系。其中,消息队列的符号很像多个邮箱。实际上,我们可以将消息队列看作时多个邮箱组成的数组,只是它们共用一个等待任务列表。每个指针所指向的数据结构是由具体的应用程序决定的。N代表了消息队列中的总单元数。当调用OSQPend()或者OSQAccept()之前,调用N次OSQPost()或者OSQPostFront()就会把消息队列填满。从图F6.7中可以看出,一个任务或者中断服务子程序可以调用OSQPost(),OSQPostFront(),OSQFlush()或者OSQAccept()函数。但是,只有任务可以调用OSQPend()和OSQQuery()函数。

图F6.7任务、中断服务子程序和消息队列之间的关系——Figure6.7
图F6.8是实现消息队列所需要的各种数据结构。这里也需要事件控制块来记录等待任务列表[F6.8(1)],而且,事件控制块可以使多个消息队列的操作和信号量操作、邮箱操作相同的代码。当建立了一个消息队列时,一个队列控制块(OS_Q结构,见OS_Q.C文件)也同时被建立,并通过OS_EVENT中的.OSEventPtr域链接到对应的事件控制块[F6.8(2)]。 在建立一个消息队列之前,必须先定义一个含有
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
