4.2节 事件模块(Event Module)
本章介绍用于同步访问共享资源的模块
目录列表如下:
4.1 信号量(Semaphores)
4.2 事件模块(Event Module)
4.3门(Gates)
4.4 邮箱(Mailboxes)
4.5 队列(Queues)
事件为线程之间的通信和同步提供了一种方法。他们类似于信号量(参见【SYS/BIOS】4.1节同步模块之信号量)只是它们允许您指定在等待线程返回之前必须发梢的多个条件(“事件”)。
事件实例的使用与信号量一样,也是调用"pend"和"post"。但是,对Event_pend()的调用还指定要等待哪些事件,对Event_post()的调用指定要传递哪些事件。
注意:一次只有1个任务可以挂起在事件对象上。
单个事件实例最多可以管理32个事件,每个事件由一个事件ID表示。事件ID是对应于事件对象管理的唯一事件的位掩码。
每个事件的行为都像一个二进制信号量。但是,有关从信号量或邮箱隐式传递(post)的事件的详细信息,请参见第4.2.1节。
有关此模块实例的参数结构和单个参数的信息,请参阅第1.6.1节中描述的API参考帮助系统.
调用Event_pend()需要一个“andMask”和一个“orMask”。andMask由所有必须发生的事件的事件ID组成,orMask由任何只有一个必须发生的事件的事件ID组成。
与信号量一样,对Event_pend()的调用采用超时值,如果调用超时,则返回0。如果对Event_pend()的调用成功,它将返回“已消耗”事件的掩码,即满足对Event_pend()调用的事件。然后,任务负责处理所有消耗的事件。
只有任务可以调用Event_pend(),而Hwis、Swis和其他任务都可以调用Event_post()。
Event_pend()原型如下:
UInt Event_pend(Event_Handle event,
UInt andMask,
UInt orMask,
UInt timeout);
Event_post()原型如下:
Void Event_post(Event_Handle event,
UInt eventIds);
调用Event_post()可能会导致在特定情况下重新启用硬件中断(Hwi)。有关详细信息,请参见第8.2.4节,启用和禁用中断。
配置示例:这些配置语句静态创建事件。事件对象有1个名为“myEvent”的事件句柄类型的事件对象。
var Event = xdc.useModule("ti.sysbios.knl.Event");
Program.global.myEvent = Event.create();
运行时示例:下面的C代码创建了一个名为“myEvent”的Event_Handle类型的事件对象。
Event_Handle myEvent;
Error_Block eb;
Error_init(&eb);
/* Default instance configuration params */
myEvent = Event_create(NULL, &eb);
if (myEvent == NULL) {
System_abort("Event create failed");
}
**运行时示
例**:下面的C代码在事件上阻塞。只有当事件0和6都发生时,它才会唤醒任务。它将andMask设置为同时启用Event_Id_00 和 Event_Id_06。它将orMask设置为Event_Id_NONE.
Event_pend(myEvent, (Event_Id_00 + Event_Id_06), Event_Id_NONE,
BIOS_WAIT_FOREVER);
运行时示例:下面的C代码调用Event_post()来指示发生了哪些事件。eventMask应该包含正在传递(post)的事件的ID。
Event_post(myEvent, Event_Id_00);
运行时示例:下面的C代码示例显示了一个任务,该任务提供三个中断服务例程所需的后台处理。
Event_Handle myEvent;
main()
{
...
/* create an Event object. All events are binary */
myEvent = Event_create(NULL, &eb);
if (myEvent == NULL) {
System_abort("Event create failed");
}
}
isr0()
{
...
Event_post(myEvent, Event_Id_00);
...
}
isr1()
{
...
Event_post(myEvent, Event_Id_01);
...
}
isr2()
{
...
Event_post(myEvent, Event_Id_02);
...
}
4.2.1 隐式发布事件
除了支持通过Event_post()API显式发布事件外,一些SYS/BIOS对象还支持隐式发布与其对象关联的事件。例如,可以将邮箱配置为每当消息可用时(即每当调用Mailbox_post()时)发布关联事件,从而允许任务在等待邮箱消息和/或某个其他事件发生时阻塞。
邮箱和信号量对象当前支持发布与其资源可用相关的事件。要启用从邮箱和信号量对象发布事件的功能,必须将信号量模块的supportsEvents属性设置为True。例如,配置可能包括以下语句:
Semaphore.supportsEvents = true;
支持隐式事件发布的SYS/BIOS对象在创建时必须配置事件对象和事件ID。您可以决定将哪个事件ID与特定的资源可用性信号(即邮箱中可用的邮件、邮箱中可用的房间或可用的信号量)关联。
注意:如前所述,一次只能在事件对象上挂起一个任务。因此,配置为隐式事件发布的SYS/BIOS对象一次只能由单个任务等待。
当使用Event_pend()从隐式发布对象获取资源是,应使用BIOS_NO_WAIT timeout参数,以便随后从该对象检索资源。
回想以下,事件是二进制的,因此从Event_pend()返回时,所有匹配的事件都会被消耗。如果任务在从信号量隐式发布的事件上被阻止,则会使用相应的事件ID。在同一个事件ID上再次立即调用Event_pend()将导致阻塞。
但是,如果在调用 Event_pend() 之前对相应的信号量调用了Semaphore_pend(sem, BIOS_NO_WAIT),对象事件中匹配的事件ID将在从Semaphore_pend()返回之前在内部刷新以匹配新更新的信号量“count”。如果调用Semaphore_pend()后,信号量计数非零,在事件对象中设置相应的事件ID。如果调用Semaphore_pend()后,计数为零,事件对象中相应的事件ID被清除。通过这种方式,事件对象与隐式调用Event_post()的信号量对象保持同步。但是为了使同步发生,应用程序必须调用 Semaphore_pend(sem, BIOS_NO_WAIT)。
由于邮箱是基于信号量构建的,所以相同的逻辑适用于想邮箱注册的事件对象。在Mailbox_post()或 Mailbox_pend()从 Event_pend() 返回隐式发布的事件之后,通过对Mailbox_pend(mbx, mbuf, BIOS_NO_WAIT) 或 Mailbox_post(mbx, mbuf, BIOS_NO_WAIT)的中间调用刷新相应的事件对象。
运行时示例:下面的C代码示例显示了一个任务,该任务处理发送到邮箱的消息,并执行ISR的后处理要求。
Event_Handle myEvent;
Mailbox_Handle mbox;
typedef struct msg {
UInt id;
Char buf[10];
}
main()
{
Mailbox_Params mboxParams;
Error_Block eb;
Error_init(&eb);
myEvent = Event_create(NULL, &eb);
if (myEvent == NULL) {
System_abort("Event create failed");
}
以上内容翻译自TI官方文档 TI-RTOS Kernel (SYS/BIOS) User’s Guide Literature Number: SPRUEX3U February 2018
翻译原文链接:https://www.ti.com.cn/cn/lit/ug/spruex3v/spruex3v.pdf
转载请注明出处