鸿蒙南向开发教程 Day 6:事件标志组(Event Flags)
/ Task1 线程 ID// Task2 线程 ID// 事件标志组 ID// 定义三个事件标志位(按位独立)// bit 0// bit 1// bit 21024// 线程栈大小1// Task1 线程 ID osThreadId_t Task2_ID;// Task2 线程 ID osEventFlagsId_t event_ID;// 事件标志组 ID // 定义三个事件标志位(按位独立
目标:掌握 OpenHarmony 轻量系统的事件标志组 API,实现多线程间的事件通知与同步
前置条件:已完成 Day 5 的延时教程
一、工程结构
app/
├── BUILD.gn
└── 04_event/ # 模块目录
├── BUILD.gn
└── demo.c # 事件标志组测试代码
1.1 app/BUILD.gn
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
"04_event:event_demo", # 引用 04_event 模块
]
}
1.2 04_event/BUILD.gn
static_library("event_demo") {
sources = [
"demo.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
}
二、完整代码详解
2.1 全局变量定义
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
osThreadId_t Task1_ID; // Task1 线程 ID
osThreadId_t Task2_ID; // Task2 线程 ID
osEventFlagsId_t event_ID; // 事件标志组 ID
// 定义三个事件标志位(按位独立)
uint32_t event1_Flags = 0x00000001U; // bit 0
uint32_t event2_Flags = 0x00000002U; // bit 1
uint32_t event3_Flags = 0x00000004U; // bit 2
#define TASK_STACK_SIZE 1024 // 线程栈大小
#define TASK_DELAY_TIME 1 // 延时 1 秒
事件标志位设计:
| 标志 | 值 | 二进制 | 含义 |
|---|---|---|---|
event1_Flags |
0x00000001U |
...0001 |
事件 1 |
event2_Flags |
0x00000002U |
...0010 |
事件 2 |
event3_Flags |
0x00000004U |
...0100 |
事件 3 |
每个事件占用独立的 bit 位,可同时设置/等待多个事件。
2.2 发送事件线程(Task1)
void Task1(void)
{
while (1) {
printf("enter Task 1.......\n");
// 设置事件标志 1
osEventFlagsSet(event_ID, event1_Flags);
printf("send eventFlag1.......\n");
sleep(TASK_DELAY_TIME); // 延时 1 秒
// 设置事件标志 2
osEventFlagsSet(event_ID, event2_Flags);
printf("send eventFlag2.......\n");
sleep(TASK_DELAY_TIME);
// 设置事件标志 3
osEventFlagsSet(event_ID, event3_Flags);
printf("send eventFlag3.......\n");
sleep(TASK_DELAY_TIME);
}
}
执行时序:
Task1: set bit0 ──sleep(1s)── set bit1 ──sleep(1s)── set bit2 ──sleep(1s)──→
"event1" "event2" "event3"
2.3 接收事件线程(Task2)
void Task2(void)
{
uint32_t flags = 0;
while (1) {
// 等待三个事件标志全部置位(AND 关系)
flags = osEventFlagsWait(
event_ID, // 事件标志组 ID
event1_Flags | event2_Flags | event3_Flags, // 等待的位掩码
osFlagsWaitAll, // 等待模式:全部置位
osWaitForever // 超时时间:永久等待
);
printf("receive event is OK\n");
}
}
等待模式详解:
| 模式 | 值 | 说明 |
|---|---|---|
osFlagsWaitAny |
0 | 或等待:任一标志置位即唤醒 |
osFlagsWaitAll |
1 | 与等待:所有标志都置位才唤醒 |
本例使用 osFlagsWaitAll:必须 bit0、bit1、bit2 全部置 1,Task2 才会唤醒。
2.4 系统入口
static void kernel_event_example(void)
{
printf("Enter kernel_event_example()!\n");
// 1. 创建事件标志组
event_ID = osEventFlagsNew(NULL); // NULL = 默认属性
if (event_ID != NULL) {
printf("ID = %d, Create event_ID is OK!\n", event_ID);
}
// 2. 配置线程属性
osThreadAttr_t taskOptions;
taskOptions.name = "Task1";
taskOptions.attr_bits = 0;
taskOptions.cb_mem = NULL;
taskOptions.cb_size = 0;
taskOptions.stack_mem = NULL;
taskOptions.stack_size = TASK_STACK_SIZE;
taskOptions.priority = osPriorityNormal;
// 3. 创建 Task1(发送事件)
Task1_ID = osThreadNew((osThreadFunc_t)Task1, NULL, &taskOptions);
if (Task1_ID != NULL) {
printf("ID = %d, Create Task1_ID is OK!\n", Task1_ID);
}
// 4. 创建 Task2(接收事件),复用 taskOptions 结构体
taskOptions.name = "Task2";
Task2_ID = osThreadNew((osThreadFunc_t)Task2, NULL, &taskOptions);
if (Task2_ID != NULL) {
printf("ID = %d, Create Task2_ID is OK!\n", Task2_ID);
}
}
SYS_RUN(kernel_event_example); // 系统启动入口
三、CMSIS-RTOS2 事件标志组 API 详解
3.1 osEventFlagsNew — 创建事件标志组
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr);
| 参数 | 说明 |
|---|---|
attr |
属性,NULL 为默认 |
返回值:事件标志组 ID,NULL 表示创建失败。
3.2 osEventFlagsSet — 设置事件标志
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags);
| 参数 | 说明 |
|---|---|
ef_id |
事件标志组 ID |
flags |
要设置的位掩码 |
特点:
- 设置后,等待该标志的线程会被唤醒(如果条件满足)
- 可一次设置多个位:
osEventFlagsSet(event_ID, flag1 | flag2)
3.3 osEventFlagsWait — 等待事件标志
uint32_t osEventFlagsWait(
osEventFlagsId_t ef_id, // 事件标志组 ID
uint32_t flags, // 等待的位掩码
uint32_t options, // 等待模式 + 清除选项
uint32_t timeout // 超时时间(tick),osWaitForever = 永久
);
options 组合:
| 选项 | 值 | 说明 |
|---|---|---|
osFlagsWaitAny |
0x00000000 | 任一标志置位即唤醒 |
osFlagsWaitAll |
0x00000001 | 所有标志置位才唤醒 |
osFlagsNoClear |
0x00000002 | 唤醒后不自动清除标志 |
常用组合:
osFlagsWaitAny:或等待,自动清除osFlagsWaitAll:与等待,自动清除(本例使用)osFlagsWaitAll | osFlagsNoClear:与等待,不清除(需手动osEventFlagsClear)
3.4 osEventFlagsClear — 清除事件标志
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags);
3.5 osEventFlagsGet — 获取当前标志值
uint32_t osEventFlagsGet(osEventFlagsId_t ef_id);
3.6 osEventFlagsDelete — 删除事件标志组
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id);
四、执行流程时序图
时间轴 →
Task1: [set bit0]────[sleep 1s]────[set bit1]────[sleep 1s]────[set bit2]────[sleep 1s]────→
"event1" "event2" "event3"
event_ID 标志位:
bit0=1 bit1=1 bit2=1
───────────────────────────────────────────────────────────────────────────────→
Task2: [wait all bits]←──────────────────────────────────────────→[wakeup!]────────────→
Blocked状态 等待bit0&bit1&bit2全部置位 "receive event is OK"
关键:Task2 在第三次 osEventFlagsSet 后才唤醒,因为前两次 bit0 和 bit1 置位时,bit2 还未置位,不满足 osFlagsWaitAll 条件。
五、底层实现:LiteOS 原生事件
CMSIS-RTOS2 的 osEventFlagsXxx 在 LiteOS-M 中的映射:
| CMSIS-RTOS2 | LiteOS-M 原生 | 说明 |
|---|---|---|
osEventFlagsNew |
LOS_EventCreate |
创建事件控制块 |
osEventFlagsSet |
LOS_EventWrite |
写事件标志 |
osEventFlagsWait |
LOS_EventRead |
读事件标志 |
osEventFlagsClear |
LOS_EventClear |
清除事件标志 |
osEventFlagsDelete |
LOS_EventDelete |
删除事件控制块 |
LiteOS-M 使用 事件控制块(Event Control Block) 实现,内部维护一个 32 位事件标志字。
六、编译与验证
6.1 编译烧录
VSCode 点击 Build → Upload,串口波特率 115200。
6.2 预期输出
Enter kernel_event_example()!
ID = 20001xxx, Create event_ID is OK!
ID = 20001yyy, Create Task1_ID is OK!
ID = 20001zzz, Create Task2_ID is OK!
enter Task 1.......
send eventFlag1.......
enter Task 1.......
send eventFlag2.......
enter Task 1.......
send eventFlag3.......
receive event is OK
enter Task 1.......
send eventFlag1.......
...
Task2 在 Task1 发送完三个事件后才打印 “receive event is OK”,验证了
osFlagsWaitAll的与等待逻辑。
七、总结
| 要点 | 内容 |
|---|---|
| 事件标志 | 32 位独立位,可同时管理多个事件 |
| 设置事件 | osEventFlagsSet(id, flags) |
| 等待事件 | osEventFlagsWait(id, flags, mode, timeout) |
| 等待模式 | osFlagsWaitAny(或)/ osFlagsWaitAll(与) |
| 自动清除 | 默认唤醒后自动清除,可加 osFlagsNoClear 保留 |
| 底层映射 | LiteOS-M LOS_EventXxx 事件控制块 |
八、下一步
Day 7 预告:信号量(Semaphore) —— 资源计数与任务同步。
更多推荐




所有评论(0)