μC/OS-II的任务之间的通讯与同步
与消息队列最大消息数相同个数的指针数组[F6.8(3)]。数组的起始地址以及数组中的元素数作为参数传递给OSQCreate()函数。事实上,如果内存占用了连续的地址空间,也没有必要非得使用指针数组结构。
文件OS_CFG.H中的常数OS_MAX_QS定义了在μC/OS-II中可以使用的最大消息队列数,这个值最小应为2。μC/OS-II在初始化时建立一个空闲的队列控制块链表,如图F6.9所示。

图F6.8用于消息队列的数据结构——Figure6.8

图F6.9空闲队列控制块链表——Figure6.9
队列控制块是一个用于维护消息队列信息的数据结构,它包含了以下的一些域。这里,仍然在各个变量前加入一个[.]来表示它们是数据结构中的一个域。
.OSQPtr在空闲队列控制块中链接所有的队列控制块。一旦建立了消息队列,该域就不再有用了。
.OSQStart是指向消息队列的指针数组的起始地址的指针。用户应用程序在使用消息队列之前必须先定义该数组。
.OSQEnd是指向消息队列结束单元的下一个地址的指针。该指针使得消息队列构成一个循环的缓冲区。
.OSQIn 是指向消息队列中插入下一条消息的位置的指针。当.OSQIn和.OSQEnd相等时,.OSQIn被调整指向消息队列的起始单元。
.OSQOut 是指向消息队列中下一个取出消息的位置的指针。当.OSQOut和.OSQEnd相等时,.OSQOut被调整指向消息队列的起始单元。
.OSQSize 是消息队列中总的单元数。该值是在建立消息队列时由用户应用程序决定的。在μC/OS-II中,该值最大可以是65,535。
.OSQEntries 是消息队列中当前的消息数量。当消息队列是空的时,该值为0。当消息队列满了以后,该值和.OSQSize值一样。在消息队列刚刚建立时,该值为0。
消息队列最根本的部分是一个循环缓冲区,如图F6.10。其中的每个单元包含一个指针。
队列未满时,.OSQIn[F6.10(1)]指向下一个存放消息的地址单元。如果队列已满(.OSQEntries
与.OSQSize相等),.OSQIn[F6.10(3)]则与.OSQOut指向同一单元。如果在.OSQIn指向的单元
插入新的指向消息的指针,就构成 FIFO(First-In-First-Out)队列。相反,如果在.OSQOut
指向的单元的下一个单元插入新的指针,就构成LIFO队列(Last-In-First-Out)[F6.10(2)]。
当.OSQEntries和.OSQSize相等时,说明队列已满。消息指针总是从.OSQOut[F6.10(4)]指向
的单元取出。指针.OSQStart和.OSQEnd [F6.10(5)]定义了消息指针数组的头尾,以便在.OSQIn
和.OSQOut到达队列的边缘时,进行边界检查和必要的指针调整,实现循环功能。

图F6.10消息队列是一个由指针组成的循环缓冲区——Figure6.10
6.8.1 建立一个消息队列,OSQCreate()
程序清单L6.21是OSQCreate()函数的源代码。该函数需要一个指针数组来容纳指向各个消息的指针。该指针数组必须声名为void类型。
OSQCreate()首先从空闲事件控制块链表中取得一个事件控制块(见图F6.3)[L6.21(1)],并对剩下的空闲事件控制块列表的指针做相应的调整,使它指向下一个空闲事件控制块[L6.21(2)]。 接着, OSQCreate()函数从空闲队列控制块列表中取出一个队列控制块[L6.21(3)]。
如果有空闲队列控制块是可以的,就对其进行初始化[L6.21(4)]。然后该函数将事件控制块的类型设置为OS_EVENT_TYPE_Q[L6.21(5)],并使其.OSEventPtr指针指向队列控制块[L6.21(6)]。OSQCreate()还要调用OSEventWaitListInit()函数对事件控制块的等待任务列表初始化[见6.01节,初始化一个事件控制块,OSEventWaitListInit()][L6.21(7)]。因为此时消息队列正在初始化,显然它的等待任务列表是空的。最后,OSQCreate()向它的调用函数返回一个指向事件控制块的指针[L6.21(9)]。该指针将在调用OSQPend(),OSQPost(),OSQPostFront(),OSQFlush(),OSQAccept()和OSQQuery()等消息队列处理函数时使用。因此,该指针可以被看作是对应消息队列的句柄。值得注意的是,如果此时没有空闲的事件控制块,OSQCreate()函数将返回一个NULL指针。如果没有队列控制块可以使用,为了不浪费事件控制块资源,OSQCreate()函数将把刚刚取得的事件控制块重新返还给空闲事件控制块列表[L6.21(8)]。
另外,消息队列一旦建立就不能再删除了。试想,如果有任务正在等待某个消息队列中的消息,而此时又删除该消息队列,将是很危险的。
程序清单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
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
