外观
事件 - 同时等待多个标志位
生活示例ll
想象一下:你在公司当技术支持,有同事们通过不同方式联系你——电话、微信、邮件。如果任何一个渠道有消息,你就需要立即响应处理。于是你规定自己:
- 每隔一小会检查一下所有渠道;
- 一旦某个渠道有消息,就立刻处理;
- 如果暂时没有消息,你就等待下一次检查。
这个“消息来了我就处理”的机制,就类似于事件机制:系统中有多个可能发生的“事件”,任务在等待事件的过程中会阻塞;而一旦事件来了,就立即被唤醒处理。
事件机制的用途
在嵌入式系统中,任务之间有时需要等待特定条件或状态的发生,例如:
- 等待按键按下;
- 等待串口收到数据;
- 等待传感器采样完成;
事件机制(event)允许任务等待一个或多个事件的触发,是一种非常灵活且效率高的任务间同步手段。
工作原理
RT-Thread 的事件机制由struct rt_event对象实现,其内部包含一个整数set字段。也就是说:
- 每个事件对象可设置32个不同的事件位(从第0位到第31位)。
- 每一个事件位表示一个具体的事件,例如bit0表示按键按下、bit表示有数据接收等。具体对应何种事件,由应用者根据实际需要自行决定。
其主要包含两个核心操作:
操作函数 | 说明 |
---|---|
send() | 发送事件,即设置某个事件位 |
recv() | 等待事件,根据设定的等待条件(任意/全部)阻塞或立即返回。在设置等待的事件时,可通过AND或OR逻辑条件来指定等待所有或任意标志位的组合。 |
我们可以用以下图示理解:
当任务等到其需要的事件之后,可通过RT_EVENT_FLAG_CLEAR标志的设置,清除相应的标志。
与信号量的区别
特性 | 信号量 | 事件机制 |
---|---|---|
支持多种信号/标志位 | 否 | 是(32个位) |
可等待多个条件同时满足 | 否 | 是(可以等待任意或全部事件发生) |
适用于复杂状态组合 | 不适合 | 适合 |
语义 | 主要是“计数” | 主要是“标志位组合” |
重复触发影响 | 一次信号触发一个任务 | 多个任务可响应同一个事件标志 |
应用示例
以下通过代码展示了如何用事件来让任务等待按键按下或串口数据到达:
#include "base.h"
#include <rtthread.h>
static struct rt_event event;
#define EVENT_KEY_PRESSED (1 << 0)
#define EVENT_UART_PRESSED (1 << 1)
void key_entry (void * param) {
while (1) {
if (key_pressed()) {
// noitify
rt_event_send(&event, EVENT_KEY_PRESSED);
}
rt_thread_mdelay(500);
}
}
void uart_entry (void * param) {
while (1) {
if (uart_available()) {
uart_read();
// notify
rt_event_send(&event, EVENT_UART_PRESSED);
}
rt_thread_mdelay(100);
}
}
void recv_entry (void * param) {
rt_uint32_t recv;
while (1) {
rt_event_recv(&event,
EVENT_KEY_PRESSED | EVENT_UART_PRESSED,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR ,
RT_WAITING_FOREVER,
&recv);
if (recv & EVENT_KEY_PRESSED) {
rt_kprintf("key pressed\n");
}
if (recv & EVENT_UART_PRESSED) {
rt_kprintf("uart data\n");
}
}
}
int main(void) {
hardware_init();
rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);
rt_thread_t t1 = rt_thread_create("key", key_entry, RT_NULL, 1024, 10, 10);
rt_thread_startup(t1);
rt_thread_t t2 = rt_thread_create("uart", uart_entry, RT_NULL, 1024, 10, 10);
rt_thread_startup(t2);
rt_thread_t t3 = rt_thread_create("recv", recv_entry, RT_NULL, 1024, 10, 10);
rt_thread_startup(t3);
return 0;
}
内容总结
从以上内容可以看出,事件具备如下优点:
优点 | 说明 |
---|---|
高效等待多个条件 | 可一次性等待多个事件满足 |
灵活组合事件触发条件 | 支持 AND / OR 模式 |
可自动清除已处理事件 | 避免重复响应 |