线程及线程消息通信

多线程软件架构

Solution 基于 RT-Thread + LVGL 构建,主要的线程如下:

Task

Priority

Stack size

Purpose Description

依赖的宏

timer

4

1536

rt_timer_create创建的定时器超时处理

usbd

8

4096

RT USING USB DEVICE消息处理

RT USING USB DEVICE

KE_EVT3

10

1024

HCI message 高优先级接受及分发(KE_MEM足够)

tbread

10

1024

touch 触摸处理

tcpip

10

4096

LWIP TCP/IP MSG处理

RT USING LWIP

bt_downvoice

11

2000

蓝牙通话下行

RT USING BT

audiovs

11

9216

audio server

AUDIO

sensor_data

12

2048

sensor数据处理

双核架构运行在LCPU上

bts

12

3072

BT 应用消息处理

RT USING BT

KE_EVT2

12

4096

HCI message 低优先级接受及分发(KE_MEM不够),
以及所有BLE消息, 包括HCI和应用消息的处理

lcd_task

12

2048

LCD msg处理

displayback_th

12

2048

A2DP 解码

bt_wq

12

3072

BT 工作队列

RT USING BT

alarmsvc

12

1024

闹钟

etx

12

1024

LWIP 网卡处理

RT USING LWIP

erx

12

1024

LWIP 网卡处理

RT USING LWIP

battery_charger_task

12

1536

电池检测

ds_mb

13

1024

data service(IPC)通信的mailbox处理

双核架构使用,52不使用

ds_proc

14

4096

data service(IPC)业务处理线程

epic_task

15

4096

渲染及推屏

lcpu_thread

19

4096

sensor timer及算法处理&&hcpu–>lcpu msg处理

双核架构运行在LCPU上

gui_thread

19

6144

UI/VLG及应用相关处理

tf_task

20

4096

TF卡热插拔检测

USING_TF_CARD

tf_thread_task

22

4096

TF卡OTA

USING_TF_CARD

sys_work

23

4096

系统工作队列

ntp_sync

25

1536

ntc 时间同步处理

RTC_SYNC USING_NTP

KE_EVT0

25

1024

HCI

bg_thread

29

4096

flash write task

tidle

31

2560

IDLE

Solution 开机后创建的核心线程如下:

  1. GUI 线程(gui_thread):负责 LVGL 界面刷新及所有 GUI 相关逻辑处理。

  2. BG 线程(bg_thread):处理低优先级耗时任务(如 Flash 写入),避免阻塞高优先级线程。

  3. LCPU 线程(lcpu_thread):负责低功耗低功耗相关逻辑与算法。若芯片芯片含物理 LCPU,线程运行于 LCPU;否则运行于 HCPU。

  4. Sensor 数据读取线程(sensor_data):负责 sensor 数据的读取,读完之后发送到 lcpu_thread 处理。

Solution 也使用以下临时线程处理任务:

  1. power_on_thread:仅在开关机动画播放时创建,动画结束后自动销毁。

  2. weather_thread:仅在 PKG_USING_WEBCLIENT 开启且且通过 Internet 获取天气应用时创建,退出后删除。

  3. temp_thread:接收到 finsh 命令时创建,处理完成后自动销毁。

  4. vid_dec:ffmpeg(如 H264)解码线程。进入视频播放应用时创建,退出后删除。

  5. ffmpeg_read:ffmpeg(如 H264)从 Flash 读帧线程。进入视频播放应用时创建,退出后删除。

注意: 多线程需通过互斥机制保护共享变量,避免数据竞争导致异常。

thread arch

线程间通信机制

线程间通过 消息队列 实现通信,流程如下:

  1. 发送方:通过专用接口发送消息(包含数据、回调函数等);

  2. 接收方:从消息队列中获取消息,调用绑定的回调函数处理;

  3. 自动释放:处理完成后,消息资源自动释放,无需手动管理。

../_images/thread_msg.png

线程消息发送接口

发送消息到GUI线程

函数: send_msg_to_gui_thread
作用: 向 GUI 线程发送消息,支持唤醒休眠中的 GUI。

rt_err_t send_msg_to_gui_thread(
    void *data,          // 待发送的数据
    uint32_t len,        // 数据长度
    void *cb,            // 消息处理回调函数(GUI线程中执行)
    uint32_t user_data,  // 自定义参数(回调中可用)
    wakeup_ui_t wakeup   // 是否唤醒GUI(NEED_WAKEUP_UI/NO_WAKEUP_UI)
);

说明:

  • 消息调用service_msg_fill封装为comm_msg_t结构,发送至 GUI 线程队列,接收线程处理完成后通过service_msg_rel进行释放

  • 若wakeup = NEED_WAKEUP_UI,会先唤醒休眠的 GUI,再处理消息;否则,直接调用处理该消息

  • 函数提供了user_data给用户,用户可以在回调函数cb中使用该参数

示例: 传感器检测到事件时,发送事件消息至 GUI 线程并唤醒界面:

// 传感器事件处理回调(转发至GUI线程)
int sensors_msg_process_in_gui_thread_cb(comm_msg_t *msg)
{
    uint16_t msg_id = (uint16_t) msg->user_data;

    if (SENSOR_APP_EVENT_ID_BEGIN < msg_id && msg_id < SENSOR_APP_EVENT_ID_END)
    {
#if defined(APP_POPUP_USED)
        popup_run("remind", (void *)msg->data);
#endif
    }

    return 0;
}

// 发送消息到GUI线程,唤醒界面并指定处理回调
send_msg_to_gui_thread(data, data_len, sensors_msg_process_in_gui_thread_cb, msg_id, NEED_WAKEUP_UI);

发送消息到 BG 线程

函数: send_msg_to_bg_thread
作用: 向 BG 线程发送低优先级任务(如硬件控制、Flash 操作)。

rt_err_t send_msg_to_bg_thread(
    void *data,          // 待发送的数据
    uint32_t len,        // 数据长度
    void *cb,            // 消息处理回调函数(BG线程中执行)
    uint32_t user_data   // 自定义参数(回调中可用)
);

示例: 控制电机开关(低优先级任务,由 BG 线程处理):

// 电机控制回调(BG线程中执行)
static int motor_control_on_cb(comm_msg_t *msg)
{
    app_motor_control_t *motor = msg->data;
    if (motor->on)
    {
        motor_power_on(1);
        motor_start();
    }
    else
    {
        motor_stop();
        motor_power_on(0);
    }

    return 0;
}

// 发送电机控制消息到BG线程
void app_motor_control(bool on, int16_t times)
{
    app_motor_control_t motor_control;

    if (motor_times > 0 && times > 0) return;
    motor_control.on = on;
    motor_times = times;

    send_msg_to_bg_thread(&motor_control, sizeof(motor_control), motor_control_on_cb, 0);
}

发送消息到 LCPU 线程

函数: send_msg_to_lcpu_thread
作用: 向 LCPU 线程发送低功耗相关任务(如传感器算法调度)。

rt_err_t send_msg_to_lcpu_thread(
    void *data,          // 待发送的数据
    uint32_t len,        // 数据长度
    void *cb,            // 消息处理回调函数(LCPU线程中执行)
    uint32_t user_data   // 自定义参数(回调中可用)
);

示例: 调度传感器算法(低功耗任务,由 LCPU 线程处理):

// 传感器调度回调(LCPU线程中执行)
static int sensor_timeout_cb(comm_msg_t *msg)
{
    uint32_t period = * ((uint32_t *) msg->data);
    gsensor_algo_scheduler(period);
    return 0;
}

// 发送调度消息到LCPU线程
void sensor_timer_handle(void *param)
{
    rt_err_t ret = send_msg_to_lcpu_thread(&sensor_time, sizeof(sensor_time), sensor_timeout_cb, 0);
}

如何新增一个线程

新增线程用于独立处理特定任务,建议参考lcpu_thread.c实现,核心步骤:

  • 定义线程入口函数:初始化消息队列,循环接收并处理消息。

  • 创建消息处理机制:封装comm_msg_t消息结构,绑定回调函数。

  • 设置线程属性:合理配置优先级(避免过高影响系统响应,或过低导致任务延迟)。

  • 定义通信接口:提供类似send_msg_to_xxx_thread的专用发送函数,方便其他线程调用。

  • 确保线程退出时释放资源(如消息队列、动态内存),避免内存泄漏。