事件
2026/7/16大约 6 分钟内核组件内核同步事件事件标志
事件
📚 本节导读
学习时长: 约 25 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 任务管理、信号量
事件(Event)是 OneOS 提供的一种强大的多对多同步机制。它使用 32 位掩码表示多个事件标志,支持 AND(逻辑与)和 OR(逻辑或)两种触发方式,可以在一个任务等待多个事件条件同时满足时使用。
🎯 学习目标
- 理解事件的核心概念:32 位事件标志、AND/OR 触发
- 掌握事件的发送(send)和接收(recv)操作
- 理解事件选项(AND/OR/CLEAR)的含义
- 掌握一对多和多对多同步模式
- 了解
os_event_sync同步发送的使用场景
一、事件概念
1.1 什么是事件
事件是一组 32 位的标志位,每一位代表一个独立的事件。任务可以等待一个或多个事件位被置位,也可以设置和清除事件位。
┌─────────────────────────────────────────────────────────────────┐
│ 事件模型 │
│ │
│ 事件标志位 (32 bits) │
│ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │
│ │31│30│29│..│ 5│ 4│ 3│ 2│ 1│ 0│ │
│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ │
│ ↑ ↑ ↑ ↑ │
│ 事件4 事件3 事件2 事件1 │
│ │
│ ┌──────────┐ send(set) ┌──────────────┐ │
│ │ 任务 A │ ───────────────→ │ │ │
│ └──────────┘ 设置事件位 │ 事件对象 │ │
│ │ ┌────────┐ │ │
│ ┌──────────┐ recv() │ │ 标志集 │ │ │
│ │ 任务 B │ ───────────────→ │ └────────┘ │ │
│ └──────────┘ 等待事件位 │ ┌────────┐ │ │
│ AND/OR 触发 │ │ 等待队列│ │ │
│ │ └────────┘ │ │
│ ┌──────────┐ recv() │ │ │
│ │ 任务 C │ ───────────────→ │ │ │
│ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘1.2 事件触发逻辑
事件支持两种触发方式:
| 触发方式 | 宏 | 含义 |
|---|---|---|
| AND(逻辑与) | OS_EVENT_OPTION_AND | 等待所有感兴趣的事件位都置位后才唤醒 |
| OR(逻辑或) | OS_EVENT_OPTION_OR | 等待任意一个感兴趣的事件位置位就唤醒 |
还可以配合清除选项:
| 选项 | 宏 | 含义 |
|---|---|---|
| CLEAR | OS_EVENT_OPTION_CLEAR | 接收事件后自动清除已满足的事件位 |
1.3 事件与信号量的对比
| 特性 | 事件 | 信号量 |
|---|---|---|
| 数据维度 | 32 位(可表示 32 个独立事件) | 1 个计数器 |
| 触发方式 | AND / OR 可选 | 仅计数 > 0 |
| 一对多同步 | 支持(一个事件可唤醒多个等待者) | 不支持(一个 post 只唤醒一个等待者) |
| 多条件组合 | 支持(等待多个事件同时满足) | 不支持 |
| 中断中使用 | 仅 send 可以 | 仅 post 可以 |
二、API 详解
以下 API 定义在 kernel/include/os_event.h 中:
#include <os_event.h>注意:使用事件需要在
oneos_config.h中启用OS_USING_EVENT宏。
2.1 事件选项宏
#define OS_EVENT_OPTION_AND 0x00000001U /* 逻辑与触发 */
#define OS_EVENT_OPTION_OR 0x00000002U /* 逻辑或触发 */
#define OS_EVENT_OPTION_CLEAR 0x00000004U /* 接收后自动清除 */
#define OS_EVENT_OPTION_MASK 0x00000007U /* 选项掩码 */2.2 静态定义
#define OS_EVENT_DEFINE(name) os_event_dummy_t name2.3 创建事件
os_event_id os_event_create(os_event_dummy_t *event_cb, const char *name);| 参数 | 说明 |
|---|---|
event_cb | 事件控制块指针。静态创建时传入 OS_EVENT_DEFINE 定义的变量地址;动态创建时传 OS_NULL |
name | 事件名称 |
| 返回值 | 成功返回事件 ID,失败返回 OS_NULL |
2.4 销毁事件
os_err_t os_event_destroy(os_event_id event_id);2.5 发送事件
os_err_t os_event_send(os_event_id event_id, uint32_t set);设置事件标志位。可以在中断上下文中调用。set 参数中的每个位对应一个事件,值为 1 表示设置该事件。
2.6 接收事件
os_err_t os_event_recv(os_event_id event_id,
uint32_t interested_set,
uint32_t option,
os_tick_t timeout,
uint32_t *recved_set);| 参数 | 说明 |
|---|---|
event_id | 事件 ID |
interested_set | 感兴趣的事件位掩码(只关心这些位) |
option | 触发选项:OS_EVENT_OPTION_AND / OS_EVENT_OPTION_OR / OS_EVENT_OPTION_CLEAR(可组合) |
timeout | 超时时间(tick 数) |
recved_set | 输出参数,返回实际接收到的事件位集合 |
| 返回值 | OS_EOK 成功;OS_ETIMEOUT 超时;OS_ERROR 错误 |
2.7 清除事件
os_err_t os_event_clear(os_event_id event_id, uint32_t interested_clear);清除指定的事件标志位。interested_clear 中为 1 的位将被清除。
2.8 获取当前事件值
os_err_t os_event_get(os_event_id event_id, uint32_t *set);获取当前所有事件标志位的值。
2.9 同步发送
os_err_t os_event_sync(os_event_id event_id,
uint32_t set,
uint32_t interested_set,
os_tick_t timeout,
uint32_t *recved_set);这是一个原子操作:先发送事件(set),然后等待指定的事件(interested_set)。相当于 os_event_send + os_event_recv 的原子组合。
2.10 唤醒策略
os_err_t os_event_set_wake_type(os_event_id event_id, uint8_t wake_type);| 唤醒类型 | 宏 | 含义 |
|---|---|---|
| 优先级唤醒 | OS_EVENT_WAKE_TYPE_PRIO (0x55) | 唤醒等待队列中优先级最高的任务 |
| FIFO 唤醒 | OS_EVENT_WAKE_TYPE_FIFO (0xAA) | 唤醒等待队列中等待时间最长的任务 |
三、代码示例
3.1 基本事件:OR 触发
#include <oneos_config.h>
#include <os_task.h>
#include <os_event.h>
#define EVENT_DATA_READY (1 << 0) /* 第 0 位:数据就绪 */
#define EVENT_UART_IDLE (1 << 1) /* 第 1 位:UART 空闲 */
#define EVENT_TIMEOUT (1 << 2) /* 第 2 位:超时事件 */
OS_EVENT_DEFINE(g_sys_event);
/* 事件发送任务 */
void event_sender_task(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
while (1)
{
os_task_sleep(1000);
/* 发送数据就绪事件 */
os_event_send(event_id, EVENT_DATA_READY);
printf("Event: DATA_READY sent\n");
os_task_sleep(500);
/* 发送 UART 空闲事件 */
os_event_send(event_id, EVENT_UART_IDLE);
printf("Event: UART_IDLE sent\n");
}
}
/* 事件接收任务:OR 触发,任意一个事件就绪即唤醒 */
void event_receiver_task(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
uint32_t recved;
while (1)
{
/* 等待 DATA_READY 或 UART_IDLE 任意一个 */
os_err_t ret = os_event_recv(event_id,
EVENT_DATA_READY | EVENT_UART_IDLE,
OS_EVENT_OPTION_OR | OS_EVENT_OPTION_CLEAR,
OS_WAIT_FOREVER,
&recved);
if (ret == OS_EOK)
{
if (recved & EVENT_DATA_READY)
printf("Receiver: processing data...\n");
if (recved & EVENT_UART_IDLE)
printf("Receiver: UART is idle now\n");
}
}
}3.2 AND 触发:等待多个条件同时满足
void event_and_receiver(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
uint32_t recved;
while (1)
{
/* 等待 DATA_READY 和 UART_IDLE 同时满足 */
os_err_t ret = os_event_recv(event_id,
EVENT_DATA_READY | EVENT_UART_IDLE,
OS_EVENT_OPTION_AND | OS_EVENT_OPTION_CLEAR,
OS_WAIT_FOREVER,
&recved);
if (ret == OS_EOK)
{
printf("Both DATA_READY and UART_IDLE are set!\n");
/* 所有条件满足,执行操作 */
}
}
}3.3 同步发送:发送并等待响应
void event_sync_example(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
uint32_t recved;
/* 发送 REQUEST 事件,并等待 RESPONSE 事件 */
os_err_t ret = os_event_sync(event_id,
EVENT_DATA_READY, /* 发送的事件 */
EVENT_UART_IDLE, /* 等待的事件 */
OS_WAIT_FOREVER, /* 超时 */
&recved); /* 收到的事件 */
if (ret == OS_EOK)
{
printf("Sync: got response!\n");
}
}3.4 一对多同步:一个事件源唤醒多个任务
/* 多个任务等待同一个事件 */
void worker_task_1(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
uint32_t recved;
while (1)
{
os_event_recv(event_id, EVENT_DATA_READY,
OS_EVENT_OPTION_OR | OS_EVENT_OPTION_CLEAR,
OS_WAIT_FOREVER, &recved);
printf("Worker 1: processing...\n");
}
}
void worker_task_2(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
uint32_t recved;
while (1)
{
os_event_recv(event_id, EVENT_DATA_READY,
OS_EVENT_OPTION_OR | OS_EVENT_OPTION_CLEAR,
OS_WAIT_FOREVER, &recved);
printf("Worker 2: processing...\n");
}
}
/* 一个任务发送事件,两个 worker 都被唤醒 */
void master_task(void *parameter)
{
os_event_id event_id = (os_event_id)parameter;
while (1)
{
os_task_sleep(2000);
/* 发送事件,所有等待该位掩码的任务都会被唤醒 */
os_event_send(event_id, EVENT_DATA_READY);
}
}📝 本节小结
事件是 OneOS 中功能最丰富的同步机制,核心要点:
- 32 位事件标志:每个位代表一个独立事件,可以同时管理 32 个事件
- AND 触发:等待所有感兴趣的事件都满足才唤醒(适合多条件同步)
- OR 触发:任意一个感兴趣的事件满足就唤醒(适合多事件响应)
- CLEAR 选项:接收后自动清除已满足的事件位
- 一对多同步:一个事件可以同时唤醒多个等待任务
- 同步发送:
os_event_sync原子地发送并等待响应,适合请求-响应模式 - 中断中只能调用
os_event_send,不能调用os_event_recv