前言

在多线程系统中,全局变量虽然简单,但存在 数据撕裂(不安全)无通知机制(低效轮询)高耦合 三大弊端。

RTOS 提供了专业的 IPC 机制来解决这些问题:

  • 传输数据:使用 邮箱 (Mailbox)消息队列 (Message Queue)

  • 控制流/异常:使用 信号 (Signal)


第一部分:邮箱 (Mailbox) —— 极速传“键”

1. 核心概念

  • 本质:RTOS 中最高效的通信方式,固定传输 4 字节(32位系统下)。

  • 载荷:只能容纳一个 rt_ubase_t 类型(无符号长整型)。

    • 传值:直接传递状态码(如 100, 0xFF)。

    • 传址(核心用法):传递大数据的内存地址(指针),实现**“零拷贝”**。

  • 缓冲:有固定深度的邮件池,发不进去或收不到可以挂起等待。

2. API 详解

(1) 创建邮箱 rt_mb_create
rt_mailbox_t rt_mb_create(const char *name, 
                          rt_size_t size, 
                          rt_uint8_t flag);
  • name: 邮箱名称(用于调试)。

  • size: 容量。指能存放多少封邮件(多少个 4 字节),而不是指字节数。

  • flag: 排队模式。

    • RT_IPC_FLAG_FIFO (推荐):先来先服务。

    • RT_IPC_FLAG_PRIO:按优先级排队。

(2) 发送邮件 rt_mb_send
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value);
  • mb: 邮箱句柄。

  • value: 邮件内容(4字节)

    • 如果是数字:直接填 100

    • 如果是指针:需要强制转换 (rt_ubase_t)ptr

(3) 接收邮件 rt_mb_recv
rt_err_t rt_mb_recv(rt_mailbox_t mb, 
                    rt_ubase_t *value, 
                    rt_int32_t timeout);
  • mb: 邮箱句柄。

  • value: 接收缓存的地址。系统会把邮件内容写到这个变量里。

  • timeout: 等待时间。

    • RT_WAITING_FOREVER: 死等(最常用,没信就睡觉)。

    • 0: 不等,没信直接返回错误。

(4) 删除邮箱 rt_mb_delete
rt_err_t rt_mb_delete(rt_mailbox_t mb);
  • 注意:如果动态申请了数据内存(malloc),删除邮箱前必须确保数据已处理或释放,否则内存泄漏。

3. “零拷贝”模式(传指针)流程

  1. 生产者rt_malloc 申请结构体内存 -> 填数据 -> rt_mb_send 发送指针。

  2. 消费者rt_mb_recv 接收指针 -> 强转为结构体 -> 读数据 -> rt_free 释放内存

    • 警示:必须谁受益谁买单(消费者释放),且必须成对出现。


第二部分:消息队列 (Message Queue) —— 稳健传“货”

1. 核心概念

  • 本质:通过 “深拷贝” (Deep Copy) 传输数据块。

  • 载荷:大小可自定义(如 10字节、128字节),发送时将源数据完整复印一份到队列缓冲区。

  • 安全性:发送完后,源数据(如局部变量)可以立即销毁,互不影响。

  • 缺点:因为涉及 memcpy,数据量大时(如 >1KB)效率远低于邮箱。

2. API 详解

(1) 创建队列 rt_mq_create
rt_mq_t rt_mq_create(const char *name,
                     rt_size_t msg_size,
                     rt_size_t max_msgs,
                     rt_uint8_t flag);
  • msg_size: 每条消息的大小(字节)。建议用 sizeof(struct MyData)

  • max_msgs: 队列深度。最多能缓存多少条消息。

  • flag: 排队模式 (FIFO / PRIO)。

(2) 发送消息 rt_mq_send
rt_err_t rt_mq_send(rt_mq_t mq, 
                    void *buffer, 
                    rt_size_t size);
  • mq: 队列句柄。

  • buffer: 数据源指针。你要发送的数据在哪里?

  • size: 数据长度。通常等于创建时的 msg_size

(3) 发送紧急消息 rt_mq_urgent
rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size);
  • 特权:这条消息会插队到队列的最前面,消费者下次读取时最先读到它。

  • 场景:发送“停止”命令。

(4) 接收消息 rt_mq_recv
rt_err_t rt_mq_recv(rt_mq_t mq, 
                    void *buffer, 
                    rt_size_t size, 
                    rt_int32_t timeout);
  • mq: 队列句柄。

  • buffer: 接收缓冲区。必须指向一块足够大的内存(通常是栈上的局部变量)。

  • size: 缓冲区大小。


第三部分:信号 (Signal) —— 强制通知(冷门但霸道)

1. 核心概念

  • 本质软中断。用于模拟操作系统层面的中断行为。

  • 特点异步。接收线程无需调用接收函数,信号一来,线程立刻被打断(类似中断服务函数),强行跳转去处理信号。

  • 用途:异常处理(除零错)、杀线程、极低频的控制命令。不适合传输数据

2. 核心 API

(1) 发送信号 rt_thread_kill
int rt_thread_kill(rt_thread_t thread, int sig);
  • thread: 目标线程的句柄(ID)。

  • sig: 信号编号。

    • 系统保留:SIGKILL (强制杀死), SIGSTOP 等。

    • 用户自定义:SIGUSR1, SIGUSR2

(2) 安装信号处理函数 rt_signal_install
rt_sighandler_t rt_signal_install(int sig, rt_sighandler_t handler);
  • 告诉系统:当收到 sig 这个信号时,请自动执行 handler 这个函数。


第四部分:选型总结(一张表)

特性 邮箱 (Mailbox) 消息队列 (Msg Queue) 信号 (Signal)
传输内容 4 字节 (数值/地址) 数据块 (结构体) 信号编号 (整数)
机制 零拷贝 (传指针) 深拷贝 (memcpy) 软中断 (异步跳转)
内存管理 需用户 malloc/free 系统自动管理缓冲区
安全性 需警惕野指针 高 (数据隔离) /
适用场景 大数据传指针、状态码 传感器数据包、串口命令 异常处理、紧急控制
一句话建议 追求极速或传大数据时用 传小结构体最省心,首选 除非处理异常,否则别用
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐