xt-sdk 文档 v1.0.3
xt-sdk 嵌入式 SDK API 参考
载入中...
搜索中...
未找到
xt_event - 发布订阅模块

版本:0.2 | 日期:2025-07-03 | 路径: components/xt_task/xt_event.h


一、概述

事件发布订阅系统,支持同步分发和异步排队两种模式。单线程环境下工作。采用 快照 + 位图 + dispatch 上下文栈 方案,回调中可自由调用 subscribe / unsubscribe / publish_sync / publish,无需担心死锁或数据竞争。

1.1 设计原则

  • 去重匹配 : (event_id, event_cb) 两元组唯一标识订阅者,重复 subscribe 只更新 user_data
  • 快照分发 : dispatch 前先快照订阅者位图,回调中修改订阅不影响本轮遍历顺序
  • 位图清除 : unsubscribe 时清除所有活跃 dispatch 帧的位图 bit,确保立即生效
  • 临界区不持锁 : 回调在临界区外执行,可自由调用 event API

1.2 依赖

依赖 用途
xtiny.h 基础类型和宏
cmsis_os2.h(可选) OS 消息队列扩展( XT_TASK_ENABLE_OS 时)

二、核心概念

  • 事件 ID : xt_event_id_t ( uint32_t ),唯一标识一个事件类型。 0 为无效值( XT_EVENT_INVALID_ID )
  • 订阅者 :通过 (event_id, event_cb) 两元组唯一标识。同一回调可订阅多个不同事件
  • 事件队列 :默认 64 个槽位( XT_EVENTQUEUE_MAX ),存储待异步分发的事件
  • 订阅者数组 :默认 64 个槽位( XT_EVENTSUBER_MAX ),存储所有订阅者

三、API 参考

以下为函数签名大纲,完整的参数说明、返回值、注意事项请查看 xt_event(事件管理) 。

3.1 生命周期

函数签名 说明
xt_err_t xt_event_setup(void) 初始化事件系统,清零队列和订阅者数组

3.2 订阅管理

函数签名 说明
xt_err_t xt_event_subscribe(xt_event_id_t event_id, xt_event_cb_t event_cb, void *user_data) 订阅事件(去重匹配,已存在则更新 user_data)
xt_err_t xt_event_unsubscribe(xt_event_id_t event_id, xt_event_cb_t event_cb) 取消订阅(匹配清除,dispatch 中立即生效)

3.3 事件发布

函数签名 说明
xt_err_t xt_event_publish(xt_event_id_t event_id, void *param) 发布事件到队列(异步,由 handler 处理)
xt_err_t xt_event_publish_sync(xt_event_id_t event_id, void *param) 同步发布事件(立即分发,支持嵌套最多 5 层)

3.4 事件处理

函数签名 说明
xt_err_t xt_event_handler(void) 处理事件队列中的所有事件(队列快照方案)
bool xt_event_ready(void) 查询事件队列是否有待处理的事件

3.5 当前事件查询

函数签名 说明
xt_event_id_t xt_event_get_current_event_id(void) 获取当前正在处理的事件 ID(仅 handler 分发期间有效)
void *xt_event_get_current_event_param(void) 获取当前事件参数(无当前事件时 assert)

兼容宏: xt_event_get_current() → xt_event_get_current_event_id() , xt_event_current_get_param() → xt_event_get_current_event_param()


四、分发机制

4.1 同步分发(publish_sync)

采用 快照 + 位图 + dispatch 上下文栈 方案:

  1. pass 1 :在临界区内遍历订阅者数组,用位图标记所有匹配当前事件 ID 的订阅者
  2. pass 2 :只看位图分发。每次回调前在临界区内快照读 cb 和 user_data , 回调在临界区外执行

回调中 xt_event_unsubscribe 会清空槽位并清除 所有活跃帧 中该槽位的位图 bit,做到立即生效。回调中 xt_event_subscribe 的新订阅者不会被插入位图,下一轮才生效。

4.2 异步分发(handler)

采用 队列快照 方案:

  1. handler 开始时在临界区内快照事件队列
  2. 只处理快照中的事件
  3. 回调中 xt_event_publish 入队的新事件留在队列中, 下次 handler 才处理

4.3 嵌套发布

回调中可以调用 xt_event_publish_sync 发布其他事件(嵌套分发),每个嵌套层有独立的 dispatch 帧和位图。深度上限 5 层,超出 assert 并返回 XT_EBUSY 。


五、已知行为与限制

行为 说明
回调中 subscribe 同一事件 新订阅者 不在 本轮 publish_sync 中被调(快照已固定),下次才被调
回调中 unsubscribe 立即生效——清空槽位 + 清除所有活跃帧位图
回调中 unsub + resub 到其他事件 位图清除防止跨事件误通知(Bug #2 回归测试覆盖)
嵌套 dispatch 中 unsub 外层事件 unsubscribe 遍历所有活跃帧清除位图(Bug #3 回归测试覆盖)
嵌套 publish_sync 最多 5 层,超出 assert
队列满 xt_event_publish assert 并返回 XT_ENOMEM
订阅满 xt_event_subscribe assert 并返回 XT_ENOMEM
subscribe 去重 相同 (event_id, event_cb) 更新 user_data
unsubscribe 不存在 返回 XT_EEMPTY

六、编译配置

宏 默认值 说明
XT_EVENTQUEUE_MAX 64 事件队列容量
XT_EVENTSUBER_MAX 64 订阅者数组容量
XT_EVENT_DISPATCH_MAX_NESTING 5 嵌套发布深度上限
XT_EVENT_CRIT_STAT/ENTRY/EXIT XT_CRIT_STAT/ENTRY/EXIT 临界区保护(可独立 override)
XT_EVENT_OSAFFINITY_ENABLE 未定义 启用线程亲和性检查
XT_TASK_ENABLE_OS 未定义 启用 OS 消息队列扩展

七、常见模式

7.1 基本用法

void on_event(void *param, void *user_data) {
printf("收到事件,参数: %p\n", param);
}
void app_init(void) {
xt_event_subscribe(MY_EVENT, on_event, NULL);
}
void app_loop(void) {
xt_event_publish(MY_EVENT, (void *)123);
xt_event_handler(); // on_event 被调用
xt_event_publish_sync(MY_EVENT, (void *)456); // on_event 立即被调用
}
xt_err_t xt_event_publish_sync(xt_event_id_t event_id, void *param)
同步发布事件(立即分发)
xt_err_t xt_event_setup(void)
初始化事件系统
xt_err_t xt_event_subscribe(xt_event_id_t event_id, xt_event_cb_t event_cb, void *user_data)
订阅事件(去重匹配)
xt_err_t xt_event_publish(xt_event_id_t event_id, void *param)
发布事件到队列(异步)
xt_err_t xt_event_handler(void)
处理事件队列中的所有事件

7.2 在事件回调中管理订阅

void manager_cb(void *param, void *user_data) {
xt_event_unsubscribe(EVENT_X, worker_cb); // 取消旧订阅(立即生效)
xt_event_subscribe(EVENT_X, new_worker_cb, p); // 订阅新回调(下次生效)
}
xt_err_t xt_event_unsubscribe(xt_event_id_t event_id, xt_event_cb_t event_cb)
取消订阅(匹配清除)

7.3 嵌套发布

void cb_a(void *param, void *user_data) {
xt_event_publish_sync(EVENT_B, param); // 嵌套分发 B
}
void cb_b(void *param, void *user_data) {
xt_event_publish_sync(EVENT_C, param); // 再嵌套分发 C
}
void init(void) {
xt_event_subscribe(EVENT_A, cb_a, NULL);
xt_event_subscribe(EVENT_B, cb_b, NULL);
xt_event_subscribe(EVENT_C, cb_c, NULL);
xt_event_publish_sync(EVENT_A, NULL);
}

八、测试

测试套件位于 tests/xt_event/ ,覆盖 7 类 30 项测试:

cd tests/xt_event
xt --target windows/simulator fullclean build
xt --target windows/simulator run

测试覆盖场景:基本功能、去重匹配、回调中重入(subscribe/unsubscribe/嵌套 publish_sync)、dispatch 位图清除(Bug #2/#3 回归)、临界区不持锁、嵌套深度限制、handler 重入。