目标:掌握 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 点击 BuildUpload,串口波特率 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) —— 资源计数与任务同步。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐