鸿蒙南向开发教程 Day 3:OpenHarmony 线程管理

目标 :掌握 OpenHarmony 轻量系统的线程创建与管理,理解 CMSIS-RTOS2 接口设计

前置条件:已完成 Day 2 的 Hello World 工程


一、工程结构

复制代码
app/
├── BUILD.gn
└── 01_thread/                  # 模块目录
    ├── BUILD.gn
    └── demo.c                  # 线程测试代码

1.1 app/BUILD.gn

gn 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
  features = [
    "01_thread:thread_demo",    # 引用 01_thread 模块
  ]
}

1.2 01_thread/BUILD.gn

gn 复制代码
static_library("thread_demo") {
    sources = [
        "demo.c"
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",  # CMSIS-RTOS2 头文件路径
    ]
}

//kernel/liteos_m/components/cmsis/2.0 是 CMSIS-RTOS2 接口的头文件目录,这是 OpenHarmony 轻量系统的关键设计。


二、完整代码详解

2.1 头文件

c 复制代码
#include <stdio.h>      // 标准输入输出
#include <unistd.h>     // UNIX 标准函数(如 sleep)
#include "ohos_init.h"  // OpenHarmony 系统初始化
#include "cmsis_os2.h"  // CMSIS-RTOS2 接口头文件

关键cmsis_os2.h 是 ARM 定义的 CMSIS-RTOS2 标准接口,不是 LiteOS 原生头文件。

2.2 宏定义

c 复制代码
#define THREAD_NUM      (1000)   // 线程循环计数上限
#define STACK_SIZE      (1024)   // 线程栈大小(字节)
#define DELAY_TICKS_20  (20)     // 20 个 tick 延时
#define DELAY_TICKS_100 (100)   // 100 个 tick 延时

2.3 线程创建辅助函数

c 复制代码
osThreadId_t newThread(char *name, osThreadFunc_t func, char *arg)
{
    osThreadAttr_t attr = {
        name,              // 线程名称
        0,                 // 属性位(保留)
        NULL,              // 控制块内存(NULL 表示自动分配)
        0,                 // 控制块大小
        NULL,              // 栈内存(NULL 表示自动分配)
        STACK_SIZE * 2,    // 栈大小(2048 字节)
        osPriorityNormal,  // 优先级:普通
        0,                 // 保留
        0                  // 保留
    };
    
    osThreadId_t tid = osThreadNew(func, (void *)arg, &attr);
    if (tid == NULL) {
        printf("[Thread Test] osThreadNew(%s) failed.\r\n", name);
    } else {
        printf("[Thread Test] osThreadNew(%s) success, thread id: %d.\r\n", name, tid);
    }
    return tid;
}

osThreadAttr_t 结构体字段

字段 说明
name 线程名称,用于调试
attr_bits 属性位,保留
cb_mem 控制块内存,NULL 自动分配
cb_size 控制块大小
stack_mem 栈内存,NULL 自动分配
stack_size 栈大小
priority 线程优先级
tz_module TrustZone 模块 ID
reserved 保留

2.4 工作线程

c 复制代码
void threadTest(char *arg)
{
    static int count = 0;
    printf("%s\r\n", arg);           // 打印传入的参数
    osThreadId_t tid = osThreadGetId();  // 获取当前线程 ID
    printf("[Thread Test] threadTest osThreadGetId, thread id:%p\r\n", tid);
    
    while (count < THREAD_NUM) {
        count++;
        printf("[Thread Test] threadTest, count: %d.\r\n", count);
        osDelay(DELAY_TICKS_20);     // 延时 20 个 tick,主动让出 CPU
    }
}

2.5 主控制线程

c 复制代码
void rtosv2_thread_main(void)
{
    // 1. 创建新线程
    osThreadId_t tid = newThread("test_thread", threadTest, "This is a test thread.");
    
    // 2. 获取线程名称
    const char *t_name = osThreadGetName(tid);
    printf("[Thread Test] osThreadGetName, thread name: %s.\r\n", t_name);
    
    // 3. 获取线程状态
    osThreadState_t state = osThreadGetState(tid);
    printf("[Thread Test] osThreadGetState, state :%d.\r\n", state);
    // 状态值:1=Running, 2=Ready, 3=Blocked, 4=Terminated, 0=Inactive
    
    // 4. 设置线程优先级
    osStatus_t status = osThreadSetPriority(tid, osPriorityNormal4);
    printf("[Thread Test] osThreadSetPriority, status: %d.\r\n", status);
    
    // 5. 获取线程优先级
    osPriority_t pri = osThreadGetPriority(tid);
    printf("[Thread Test] osThreadGetPriority, priority: %d.\r\n", pri);
    
    // 6. 挂起线程(暂停执行)
    status = osThreadSuspend(tid);
    printf("[Thread Test] osThreadSuspend, status: %d.\r\n", status);
    
    // 7. 恢复线程(继续执行)
    status = osThreadResume(tid);
    printf("[Thread Test] osThreadResume, status: %d.\r\n", status);
    
    // 8. 获取栈大小
    uint32_t stack_size = osThreadGetStackSize(tid);
    printf("[Thread Test] osThreadGetStackSize, stack size: %d.\r\n", stack_size);
    
    // 9. 获取栈剩余空间
    uint32_t stack_space = osThreadGetStackSpace(tid);
    printf("[Thread Test] osThreadGetStackSpace, stack space: %d.\r\n", stack_space);
    
    // 10. 获取系统中线程总数
    uint32_t count = osThreadGetCount();
    printf("[Thread Test] osThreadGetCount, thread count: %d.\r\n", count);
    
    // 延时 100 tick
    osDelay(DELAY_TICKS_100);
    
    // 再次挂起线程
    status = osThreadSuspend(tid);
    printf("[Thread Test] osThreadSuspend, status: %d.\r\n", status);
}

2.6 系统入口

c 复制代码
static void ThreadTestTask(void)
{
    osThreadAttr_t attr;

    attr.name = "rtosv2_thread_main";
    attr.attr_bits = 0;
    attr.cb_mem = NULL;
    attr.cb_size = 0;
    attr.stack_mem = NULL;
    attr.stack_size = STACK_SIZE;
    attr.priority = osPriorityNormal;

    if (osThreadNew((osThreadFunc_t)rtosv2_thread_main, NULL, &attr) == NULL) {
        printf("[Thread Test] Failed to create thread: rtosv2_thread_main.\r\n");
    }
}

APP_FEATURE_INIT(ThreadTestTask);   // 注册为应用初始化入口

APP_FEATURE_INITSYS_RUN 的区别:

  • SYS_RUN:系统启动时执行,优先级较高
  • APP_FEATURE_INIT:应用初始化阶段执行,适合创建应用线程

三、CMSIS-RTOS2 API 速查表

函数 功能 对应 LiteOS 原生
osThreadNew 创建线程 LOS_TaskCreate
osThreadGetId 获取当前线程 ID LOS_CurTaskIDGet
osThreadGetName 获取线程名称 LOS_TaskNameGet
osThreadGetState 获取线程状态 LOS_TaskStatusGet
osThreadSetPriority 设置优先级 LOS_TaskPriSet
osThreadGetPriority 获取优先级 LOS_TaskPriGet
osThreadSuspend 挂起线程 LOS_TaskSuspend
osThreadResume 恢复线程 LOS_TaskResume
osThreadGetStackSize 获取栈大小 -
osThreadGetStackSpace 获取栈剩余空间 LOS_TaskStackWaterLineGet
osThreadGetCount 获取线程总数 LOS_TaskTotalNumGet
osDelay 延时(tick) LOS_TaskDelay

四、核心问题:为什么 OpenHarmony 使用 CMSIS-RTOS2 而不是 LiteOS 原生 Task?

4.1 什么是 CMSIS-RTOS2?

CMSIS (Cortex Microcontroller Software Interface Standard)是 ARM 推出的 Cortex-M 微控制器软件接口标准

CMSIS-RTOS2 是其中的 RTOS 接口层规范 ,定义了一套统一的 API,让上层应用代码可以不依赖具体的 RTOS 内核

4.2 设计架构

复制代码
┌─────────────────────────────────────────┐
│         应用层(你的代码)                │
│    printf, GPIO, 传感器驱动, 网络协议...   │
├─────────────────────────────────────────┤
│         CMSIS-RTOS2 接口层               │  ← 你调用的 osThreadNew, osDelay...
│    #include "cmsis_os2.h"              │
├─────────────────────────────────────────┤
│         OpenHarmony 适配层               │  ← 将 CMSIS API 映射到具体内核
│    //kernel/liteos_m/components/cmsis/2.0 │
├─────────────────────────────────────────┤
│         内核层(LiteOS-M)                │  ← LOS_TaskCreate, LOS_TaskDelay...
│    //kernel/liteos_m/kernel/...          │
└─────────────────────────────────────────┘

4.3 为什么不用 LiteOS 原生 API?

原因 说明
可移植性 CMSIS-RTOS2 是 ARM 标准,代码可在任何支持 CMSIS 的 RTOS 上运行(FreeRTOS、RT-Thread、LiteOS 等)
生态兼容 大量第三方库和中间件基于 CMSIS-RTOS2 编写,直接兼容
降低学习成本 开发者只需学一套 API,不用关心底层是哪个 RTOS
内核可替换 OpenHarmony 未来可以切换内核(如从 LiteOS 换到 FreeRTOS),上层代码无需修改
标准化 ARM 统一维护,文档完善,社区支持广泛

4.4 与 FreeRTOS 的关系

注意 :CMSIS-RTOS2 不是 FreeRTOS,它是一个接口标准

  • FreeRTOS 是一个具体的 RTOS 内核(和 LiteOS 同级)
  • CMSIS-RTOS2 是一套 API 规范
  • OpenHarmony 的 LiteOS-M 实现了 CMSIS-RTOS2 接口

也就是说:

  • 你调用 osThreadNew() → OpenHarmony 的 CMSIS 适配层 → 内部调用 LOS_TaskCreate()
  • 如果你在 FreeRTOS 上调用 osThreadNew() → FreeRTOS 的 CMSIS 适配层 → 内部调用 xTaskCreate()

同样的代码,不同的内核,行为一致。

4.5 为什么不叫 "FreeRTOS(cmsis)"?

这是一个常见的误解。准确的说法是:

OpenHarmony 轻量系统使用 LiteOS-M 内核,通过 CMSIS-RTOS2 接口 暴露给上层。

之所以有人误以为是 FreeRTOS,是因为:

  1. CMSIS-RTOS2 的 API 命名风格(osThreadXxx, osDelay)和 FreeRTOS 类似
  2. 两者都源自 ARM 生态
  3. 部分文档翻译不够精确

实际上 ,OpenHarmony 轻量系统的内核是 LiteOS-M (华为自研),标准系统的内核是 Linux


五、编译与验证

5.1 编译

VSCode 点击 Build,编译成功后烧录。

5.2 串口输出

波特率 115200,重启开发板:

复制代码
[Thread Test] osThreadNew(test_thread) success, thread id: 3.
This is a test thread.
[Thread Test] threadTest osThreadGetId, thread id:0x3
[Thread Test] osThreadGetName, thread name: test_thread.
[Thread Test] osThreadGetState, state :1.        // 1 = Running
[Thread Test] osThreadSetPriority, status: 0.    // 0 = osOK
[Thread Test] osThreadGetPriority, priority: 24.   // osPriorityNormal4
[Thread Test] osThreadSuspend, status: 0.
[Thread Test] osThreadResume, status: 0.
[Thread Test] osThreadGetStackSize, stack size: 2048.
[Thread Test] osThreadGetStackSpace, stack space: 1024.
[Thread Test] osThreadGetCount, thread count: 4.
[Thread Test] threadTest, count: 1.
[Thread Test] threadTest, count: 2.
...

六、总结

要点 内容
接口层 cmsis_os2.h 是标准接口,不是具体 RTOS
内核 OpenHarmony 轻量系统底层是 LiteOS-M
设计目的 解耦应用与内核,提高可移植性
常用 API osThreadNew, osDelay, osThreadSuspend, osThreadResume
入口宏 APP_FEATURE_INIT 用于应用初始化

七、下一步

Day 4 预告:互斥锁与信号量 ------ 多线程同步与资源保护。

相关推荐
想你依然心痛1 小时前
HarmonyOS 6(API 23)实战:打造“光味智厨“——AI烹饪新体验
人工智能·华为·ar·harmonyos·智能体
颜淡慕潇2 小时前
低成本搭建鸿蒙PC运行环境:基于 Docker 的 x86_64 服务器
服务器·docker·harmonyos
慧海灵舟3 小时前
鸿蒙南向开发教程 Day 6:事件标志组(Event Flags)
华为·harmonyos
weixin_604236673 小时前
华为三层交换机 极简完整版配置
运维·服务器·华为·华为交换机·华为交换机命令
慧海灵舟3 小时前
鸿蒙南向开发教程 Day 5:延时与系统节拍
华为·harmonyos
2501_919749034 小时前
鸿蒙 Flutter 实战:saver_gallery 5.1.0 适配 3.27-ohos 全流程
flutter·华为·harmonyos
无限码力4 小时前
华为非AI方向笔试真题 - 任意矩形图案解锁路径验证
华为·华为非ai方向笔试真题·华为笔试真题·华为最新笔试真题
co_wait4 小时前
【华为】OSPF协议Stub和NSSA区域
华为
前端不太难4 小时前
鸿蒙游戏需要 GameEngine 吗?
游戏·状态模式·harmonyos