事件集
本文档根据《嘉楠K230开发手册》V1.0(2024-11-30)整理。正文、表格、示例代码与插图均来自原始手册。
学校组织秋游,组长在等待:
- 张三:我到了
- 李四:我到了
- 王五:我到了
- 组长说:好,大家都到齐了,出发!
秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的。
在这个日常生活场景中:
- 出发:要等待这3个人都到齐,他们是"与"的关系
- 交报告:只需等待这3人中的任何一个,他们是"或"的关系
在RT-Thread中,可以使用事件集(event group)来解决这些问题。
本章涉及如下内容:
- 事件集的概念与操作函数
- 事件集的优缺点
- 怎么设置、等待、清除事件集中的位
- 使用事件集来同步多个任务
事件集概念与操作
事件集的概念
事件集可以简单地认为就是一个整数:
- 每一位表示一个事件
- 每一位事件的含义由程序员决定,比如:Bit0表示用来串口是否就绪,Bit1表示按键是否被按下
- 这些位,值为1表示事件发生了,值为0表示事件没发生
- 一个或多个线程、ISR都可以去写这些位;一个或多个线程、ISR都可以去读这些位
- 可以等待某些位中的任意一个,也可以等待多位

线程可以等待事件集:
- 某些事件中的任意一个发生了
- 某些事件中的所有事件都发生了
一个线程,怎么表达它的需求?
每个线程都有一个rt_thread结构体,它里面有如下2个成员:
struct rt_thread{ ......##if defined(RT_USING_EVENT) /* thread event */ rt_uint32_t event_set; rt_uint8_t event_info;##endif ......}
这两个成员的作用如下:
- event_set:想等待哪些事件?
- 可以设置对应的位,比如设置为
(1 << 30) | (1 << 0),表示等待事件 0、事件 30 - 那么,它想等待事件0、事件30都发生呢,还是只要事件0、事件30任意一个发生即可?
- 需要使用event_info进一步描述
- event_info:有3种取值
- RT_EVENT_FLAG_AND:逻辑与,比如事件0、事件30都发生时,才满足它的期待
- RT_EVENT_FLAG_OR:逻辑或,比如事件0、事件30发生了任何一个,都满足它的期待
- RT_EVENT_FLAG_CLEAR:等到期待的事件后,是否清除事件
事件集的操作
事件集和队列、信号量等不太一样,主要集中在2个地方:
- 唤醒谁?
- 队列、信号量 :事件发生时,只会唤醒一个线程
- 事件集:事件发生时,会唤醒所有符号条件的线程,简单地说它有"广播"的作用
- 队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了
- 事件集:被唤醒的线程有两个选择,可以让事件保留不动,也可以清除事件
以上图为列,事件集的常规操作如下:
- 先创建事件集
- 线程C、D等待事件:
- 等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。简单地说就是"或"、"与"的关系。
- 得到事件时,要不要清除?可选择清除、不清除。
- 线程A、B产生事件:设置事件集里的某一位、某些位
事件集函数
创建/初始化
使用事件集之前,要先创建,得到一个句柄;使用事件集时,要使用句柄来表明使用哪个事件集。

事件集的创建有两种方法:动态分配内存、静态分配内存,
- 动态分配内存:rt_event_create,从对象管理器中分配一个 event对象,并初始化这个对象
- 静态分配内存:rt_event_init,事件集在编译时由编译器分配
**rt_event_create()**函数原型如下:
rt_event_t rt_event_create(const char* name, rt_uint8_t flag);
| 参数 | 说明 |
|---|---|
| name | 事件集名称 |
| flag | 事件集标志,可选: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
| 返回值 | 事件集句柄:成功,返回句柄,以后使用句柄来操作事件集RT_NULL:失败 |
**rt_event_init()**函数原型如下:
rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);
| 参数 | 说明 |
|---|---|
| mutex | 事件集对象的句柄 |
| name | 事件集名称 |
| flag | 事件集标志,可选: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
| 返回值 | RT_EOK:成功 |
删除/脱离
不再使用一个事件集时:
- 删除它:rt_event_delete(),只能删除使用**rt_event_create()**创建的事件集
- 脱离它:rt_event_detach(),只能脱离使用**rt_event_init()**初始化的事件集
删除事件集的函数为,它会释放内存。原型如下:
rt_err_t rt_event_delete(rt_event_t event);
删除事件集时,如果有线程在等待该事件集,则内核会先唤醒这些线程(线程返回值是 - RT_ERROR),然后再释放事件集使用的内存,最后删除事件集对象。
脱离事件集,就是将事件集对象被从内核对象管理器中脱离。原型如下:
rt_err_t rt_event_detach(rt_event_t event);
脱离事件集时,如果有线程在等待该事件集,则内核会先唤醒这些线程(线程返回值是 - RT_ERROR)。