judy 在 提交
Mailboxes(邮箱)
ti.sysbios.knl.Mailbox模块提供了一系列函数管理mailboxes。Mailboxes可用于在相同处理器的两个task中传递缓冲。一个Mailbox实例可用于多个readers和writers。
Mailbox模块拷贝缓冲到合适尺寸的内部缓冲。这些缓冲的尺寸和个数在Mailbox实例创建时指定。拷贝在通过Mailbox_post()发送缓冲时建立。另外一份拷贝在通过Mailbox_pend()接收缓冲时建立。
Mailbox_create()和Mailbox_delete()分别用于创建和删除mailboxes。你也可以静态地创建mailbox对象。Mailbox可用于确保输入缓冲流不会超过系统处理那些缓冲的能力。本节稍后给出的例子演示了这种设计。
在创建mailbox时,你可以为每个缓冲指定其尺寸以及内部mailbox缓冲的个数。在创建Mailbox时确定尺寸之后,所有Mailbox的发送和接收缓冲必须使用这个相同的尺寸。
Mailbox_Handle Mailbox_create(SizeT bufsize,
UInt numBufs,
Mailbox_Params *params,
Error_Block *eb)
Void Mailbox_delete(Mailbox_Handle *handle);
Mailbox_pend()用于从mailbox中读取一个缓冲。如果无缓冲可用(也就是mailbox是空的),Mailbox_pend()阻塞。timeout参数为允许task等待的时间,无限期等待(BIOS_WAIT_FOREVER),或根本不等待(BIOS_NO_WAIT)。时间单位为系统时钟ticks。
Bool Mailbox_pend(Mailbox_Handle handle,
Ptr buf,
UInt timeout);
Mailbox_post()用于提交缓冲给mailbox。如果无缓冲槽可用(也就是mailbox满了),Mailbox_post()阻塞。timeout参数为允许task等待的时间,无限期等待(BIOS_WAIT_FOREVER),或根本不等待(BIOS_NO_WAIT)。
Bool Mailbox_post(Mailbox_Handle handle,
Ptr buf,
UInt timeout);
Mailbox提供了配置参数允许你将事件关联到mailbox。这使得你可以在同一时间可等待mailbox消息和其它事件。Mailbox提供两个配置参数以支持mailbox的reader的事件----readerEvent和readerEventId。这使得mailbox reader可以使用事件对象去等待mailbox消息。Mailbox还提供了两个配置参数用于mailbox writer---writerEvent和writerEventId。这使得mailbox writer可使用事件对象等待mailbox的room(room可理解为缓冲槽)。
注意,这些事件句柄的名称可能会有误导性。readerEvent是Mailbox reader请求的事件,但它是在Mailbox_post()调用中被Mailbox writer提交的。writeEvent是Mailbox writer请求等待Mailbox有空位的事件,所以在Mailbox不满时它可以成功执行Mailbox_post()。无论何时,只要Mailbox成功读取,Mailbox reader都会提交writerEvent(也就是说Mailbox_pend()返回TRUE)。
当使用事件时,一个线程调用Event_pend()并等待数个事件。在从Event_pend()返回的时候,线程必须调用Mailbox_pend()或Mailbox_post()---取决于它是reader还是writer---timeout参数为BIOS_NO_WAIT。参考4.2.1节的代码实例,它包含返回Event_pend()后的相应的Mailbox资源。
Queues(队列)
ti.sysbios.knl.Queue模块提供了对创建对象列表的支持。队列实现为双向链表,所以元素在列表中可以插入和删除,另外,队列没最大尺寸限制。
基础FIFO(先进先出)队列操作
添加一个结构体进入队列,第一个字段需要是Queue_Elem类型。下例显示了一个可被加入Queue的结构体。
队列有一个“头”,在列表的最前端。Queue_enqueue()将元素添加到列表未尾,Queue_dequeue()移除并返回列表前端元素,这些函数支持队列的FIFO操作。
运行时例子:下例演示了基于队列的操作---Queue_enqueue()和Queue_dequeue()。它也使用了Queue_empty()函数,当队列中没有元素时返回true。
/* This structure can be added to a Queue because the first field is a Queue_Elem. */
typedef struct Rec
{
Queue_Elem elem;
Int data;
} Rec;
Queue_Handle myQ;
Rec r1, r2;
Rec *rp;
r1.data = 100;
r2.data = 200;
// No parameters or Error block are needed to create a Queue.
myQ = Queue_create(NULL, NULL);
// Add r1 and r2 to the back of myQ.
Queue_enqueue(myQ, &(r1.elem));
Queue_enqueue(myQ, &(r2.elem));
// Dequeue the records and print their data
while (!Queue_empty(myQ))
{
// Implicit cast from (Queue_Elem *) to (Rec *)
rp = Queue_dequeue(myQ);
System_printf("rec: %d\n", rp->data);
}
此例打印结果如下:
rec: 100
rec: 200
队列的迭代
队列模块还提供了几个APIs用于循环访问队列。Queue_head()返回队列的前端元素且不移除它,Queue_next()和Queue_prev()分别返回队列中的下一个和前一个元素。
运行时实例:以下代码演示了一种遍历队列的方法。此例中,“myQ”是一个Queue_Handle。
Queue_Elem *elem;
for (elem = Queue_head(myQ); elem != (Queue_Elem *)myQ;
elem = Queue_next(elem))
{
...
}
插入和移除队列元素
使用Queue_insert()和Queue_remove()可以在队列中的任何位置插入或移除元素。Queue_insert()在指定元素前插入一个元素,Queue_remove()删除一个指定元素,无论它在队列中的哪个位置。注意,队列不提供任何APIs用于在给定索引入插入或移除元素。
运行时例子:下例演示了Queue_insert()和Queue_remove()。
Queue_enqueue(myQ, &(r1.elem));
/* Insert r2 in front of r1 in the Queue. */
Queue_insert(&(r1.elem), &(r2.elem));
/* Remove r1 from the Queue. Note that Queue_remove() does not
* require a handle to myQ. */
Queue_remove(&(r1.elem));
原子队列操作
队列通常在系统中通常由多个线程共享,这可能导致不同线程同时更改队列,这将破坏队列。上述讨论的队列APIs不保护这些。然而,队列提供了两个原子APIs,它可以在操作队列前禁用中断。这些APIs是Queue_get(),它是Queue_dequeue()和Queue_put()的原子操作版本,也是Queue_enqueue()的原子版本。
出处: abatei的专栏