邮箱
2026/7/16大约 6 分钟内核组件内核通信邮箱
邮箱
📚 本节导读
学习时长: 约 20 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 任务管理、信号量、消息队列
邮箱(Mailbox)是 OneOS 中一种轻量级的消息传递机制。与消息队列传递变长数据块不同,邮箱传递的是固定大小的值(os_ubase_t 类型),通常用于传递指针、句柄或整数值。由于不涉及数据拷贝,邮箱的效率比消息队列更高。
🎯 学习目标
- 理解邮箱与消息队列的核心区别
- 掌握邮箱的创建、发送和接收操作
- 了解邮箱适合的使用场景(指针传递)
- 能够使用邮箱实现高性能任务间通信
一、邮箱概念
1.1 什么是邮箱
邮箱维护一个固定大小的环形缓冲区,每个槽位存储一个 os_ubase_t 类型的值。发送方将值写入邮箱,接收方从邮箱中取出。邮箱传递的是值本身,而非数据拷贝。
┌─────────────────────────────────────────────────────────────────┐
│ 邮箱模型 │
│ │
│ ┌──────────┐ send(value) ┌──────────────────────┐ │
│ │ 任务 A │ ────────────────→ │ 邮 箱 │ │
│ │(发送者) │ 发送指针值 │ ┌───┬───┬───┬───┐ │ │
│ └──────────┘ │ │ptr│ptr│ptr│ptr│ │ │
│ │ │ 1 │ 2 │ 3 │ 4 │ │ │
│ ┌──────────┐ recv(&value) │ └───┴───┴───┴───┘ │ │
│ │ 任务 B │ ←──────────────── │ │ │
│ │(接收者) │ 取出指针值 │ 每个槽位: os_ubase_t │ │
│ └──────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘1.2 邮箱 vs 消息队列
| 特性 | 邮箱 | 消息队列 |
|---|---|---|
| 传递内容 | os_ubase_t 值(指针大小) | 任意大小的数据块 |
| 数据拷贝 | 否(只拷贝值本身) | 是(拷贝整个数据块) |
| 每个槽位大小 | 固定 sizeof(os_ubase_t) | 用户指定 msg_size |
| 性能 | 更高(无内存拷贝开销) | 有拷贝开销 |
| 典型用途 | 传递指针、句柄、整数值 | 传递数据块、结构体 |
| 内存池大小 | mail_count * sizeof(os_ubase_t) | 见消息队列内存池计算 |
1.3 使用场景
邮箱最适合以下场景:
- 传递内存块指针:发送方分配内存,将指针通过邮箱发给接收方,接收方处理完释放
- 传递句柄:将设备句柄、文件句柄等传递给其他任务
- 传递事件数据:用简单的整数值编码事件类型,比事件标志位更灵活
- 固定大小的消息:如果消息内容始终是指针大小的值,邮箱比消息队列更高效
二、API 详解
以下 API 定义在 kernel/include/os_mb.h 中:
#include <os_mb.h>注意:使用邮箱需要在
oneos_config.h中启用OS_USING_MAILBOX宏。动态创建还需要OS_USING_HEAP。
2.1 静态定义宏
#define OS_MAILBOX_DEFINE(name) os_mailbox_dummy_t name /* 定义邮箱控制块 */
#define OS_MAILBOX_POOL_DEFINE(name, mail_count) os_ubase_t pool_##name[mail_count] /* 定义邮件池 */
#define OS_MAILBOX_POOL_ADDR(name) ((void *)pool_##name) /* 获取邮件池地址 */
#define OS_MAILBOX_POOL_SIZE(name) sizeof(pool_##name) /* 获取邮件池大小 */2.2 动态创建
os_mailbox_id os_mailbox_create_dynamic(const char *name, os_size_t max_mails);| 参数 | 说明 |
|---|---|
name | 邮箱名称 |
max_mails | 邮箱能够容纳的最大邮件数(槽位数) |
| 返回值 | 成功返回邮箱 ID,失败返回 OS_NULL |
需要启用
OS_USING_HEAP。
2.3 静态创建
os_mailbox_id os_mailbox_create_static(os_mailbox_dummy_t *mailbox_cb,
const char *name,
void *mail_pool,
os_size_t mail_pool_size);| 参数 | 说明 |
|---|---|
mailbox_cb | 邮箱控制块指针(OS_MAILBOX_DEFINE 定义的变量地址) |
name | 邮箱名称 |
mail_pool | 邮件池地址(OS_MAILBOX_POOL_ADDR 获取) |
mail_pool_size | 邮件池大小(OS_MAILBOX_POOL_SIZE 获取) |
| 返回值 | 成功返回邮箱 ID,失败返回 OS_NULL |
2.4 销毁邮箱
os_err_t os_mailbox_destroy(os_mailbox_id mailbox_id);2.5 发送邮件
os_err_t os_mailbox_send(os_mailbox_id mailbox_id, os_ubase_t value, os_tick_t timeout);| 参数 | 说明 |
|---|---|
mailbox_id | 邮箱 ID |
value | 要发送的邮件值(指针或整数值) |
timeout | 超时时间。邮箱满时等待空闲槽位的时间 |
| 返回值 | OS_EOK 成功;OS_ETIMEOUT 超时;OS_EFULL 邮箱满 |
2.6 接收邮件
os_err_t os_mailbox_recv(os_mailbox_id mailbox_id, os_ubase_t *value, os_tick_t timeout);| 参数 | 说明 |
|---|---|
mailbox_id | 邮箱 ID |
value | 输出参数,接收到的邮件值 |
timeout | 超时时间 |
| 返回值 | OS_EOK 成功;OS_ETIMEOUT 超时;OS_EEMPTY 邮箱空 |
2.7 查询与管理函数
os_err_t os_mailbox_set_wake_type(os_mailbox_id mailbox_id, uint8_t wake_type);
os_err_t os_mailbox_reset(os_mailbox_id mailbox_id);
os_err_t os_mailbox_is_empty(os_mailbox_id mailbox_id, os_bool_t *empty_flag);
os_err_t os_mailbox_is_full(os_mailbox_id mailbox_id, os_bool_t *full_flag);
os_err_t os_mailbox_get_capacity(os_mailbox_id mailbox_id, uint16_t *capacity);
os_err_t os_mailbox_get_used_mails(os_mailbox_id mailbox_id, uint16_t *used_mails);
os_err_t os_mailbox_get_unused_mails(os_mailbox_id mailbox_id, uint16_t *unused_mails);| 函数 | 说明 |
|---|---|
os_mailbox_set_wake_type | 设置唤醒策略:OS_MB_WAKE_TYPE_PRIO 或 OS_MB_WAKE_TYPE_FIFO |
os_mailbox_reset | 重置邮箱,清空所有邮件 |
os_mailbox_is_empty | 检查邮箱是否为空 |
os_mailbox_is_full | 检查邮箱是否已满 |
os_mailbox_get_capacity | 获取邮箱总容量 |
os_mailbox_get_used_mails | 获取已使用的邮件数 |
os_mailbox_get_unused_mails | 获取剩余可用的邮件数 |
三、代码示例
3.1 基本使用:传递指针
#include <oneos_config.h>
#include <os_task.h>
#include <os_mb.h>
#define MAX_MAILS 16
typedef struct
{
int id;
char message[32];
} work_item_t;
OS_MAILBOX_DEFINE(g_work_mb);
OS_MAILBOX_POOL_DEFINE(g_work_mb, MAX_MAILS);
/* 生产者:分配内存并通过邮箱发送指针 */
void producer_task(void *parameter)
{
os_mailbox_id mb_id = (os_mailbox_id)parameter;
static int id = 0;
while (1)
{
/* 动态分配工作项 */
work_item_t *item = (work_item_t *)malloc(sizeof(work_item_t));
if (item == OS_NULL)
continue;
item->id = id++;
snprintf(item->message, sizeof(item->message), "Work item #%d", item->id);
/* 通过邮箱发送指针 */
os_err_t ret = os_mailbox_send(mb_id, (os_ubase_t)item, OS_WAIT_FOREVER);
if (ret == OS_EOK)
printf("Producer: sent item %d\n", item->id);
os_task_sleep(500);
}
}
/* 消费者:接收指针并处理 */
void consumer_task(void *parameter)
{
os_mailbox_id mb_id = (os_mailbox_id)parameter;
os_ubase_t value;
while (1)
{
os_err_t ret = os_mailbox_recv(mb_id, &value, OS_WAIT_FOREVER);
if (ret == OS_EOK)
{
work_item_t *item = (work_item_t *)value;
printf("Consumer: processing %s\n", item->message);
/* 处理完成后释放内存 */
free(item);
}
}
}
void mailbox_example(void)
{
os_mailbox_id mb_id;
/* 静态创建邮箱 */
mb_id = os_mailbox_create_static(
&g_work_mb,
"work_mb",
OS_MAILBOX_POOL_ADDR(g_work_mb),
OS_MAILBOX_POOL_SIZE(g_work_mb)
);
/* 创建生产者和消费者任务 */
/* ... os_task_create(...) */
}3.2 传递整数值
OS_MAILBOX_DEFINE(g_cmd_mb);
OS_MAILBOX_POOL_DEFINE(g_cmd_mb, 8);
#define CMD_START 1
#define CMD_STOP 2
#define CMD_RESET 3
#define CMD_SHUTDOWN 4
void command_sender(void *parameter)
{
os_mailbox_id mb_id = (os_mailbox_id)parameter;
/* 发送命令 */
os_mailbox_send(mb_id, CMD_START, OS_NO_WAIT);
os_task_sleep(1000);
os_mailbox_send(mb_id, CMD_RESET, OS_NO_WAIT);
os_task_sleep(1000);
os_mailbox_send(mb_id, CMD_STOP, OS_NO_WAIT);
}
void command_handler(void *parameter)
{
os_mailbox_id mb_id = (os_mailbox_id)parameter;
os_ubase_t cmd;
while (1)
{
os_err_t ret = os_mailbox_recv(mb_id, &cmd, OS_WAIT_FOREVER);
if (ret == OS_EOK)
{
switch (cmd)
{
case CMD_START:
printf("Executing START command\n");
break;
case CMD_STOP:
printf("Executing STOP command\n");
break;
case CMD_RESET:
printf("Executing RESET command\n");
break;
case CMD_SHUTDOWN:
printf("Executing SHUTDOWN command\n");
break;
default:
printf("Unknown command: %lu\n", cmd);
break;
}
}
}
}3.3 动态创建邮箱
void mailbox_dynamic_example(void)
{
os_mailbox_id mb_id;
/* 动态创建邮箱,容量 10 封邮件 */
mb_id = os_mailbox_create_dynamic("dynamic_mb", 10);
if (mb_id == OS_NULL)
{
printf("Failed to create mailbox\n");
return;
}
/* 发送邮件 */
os_mailbox_send(mb_id, (os_ubase_t)0x12345678, OS_NO_WAIT);
/* 接收邮件 */
os_ubase_t value;
os_mailbox_recv(mb_id, &value, OS_NO_WAIT);
printf("Received: 0x%08lX\n", value);
/* 销毁邮箱 */
os_mailbox_destroy(mb_id);
}3.4 查询邮箱状态
void mailbox_status_example(os_mailbox_id mb_id)
{
os_bool_t empty_flag;
os_bool_t full_flag;
uint16_t capacity;
uint16_t used;
uint16_t unused;
os_mailbox_is_empty(mb_id, &empty_flag);
os_mailbox_is_full(mb_id, &full_flag);
os_mailbox_get_capacity(mb_id, &capacity);
os_mailbox_get_used_mails(mb_id, &used);
os_mailbox_get_unused_mails(mb_id, &unused);
printf("Mailbox: empty=%d, full=%d, capacity=%d, used=%d, free=%d\n",
empty_flag, full_flag, capacity, used, unused);
}3.5 重置邮箱
void mailbox_reset_example(os_mailbox_id mb_id)
{
/* 发送一些邮件 */
os_mailbox_send(mb_id, (os_ubase_t)1, OS_NO_WAIT);
os_mailbox_send(mb_id, (os_ubase_t)2, OS_NO_WAIT);
os_mailbox_send(mb_id, (os_ubase_t)3, OS_NO_WAIT);
uint16_t used;
os_mailbox_get_used_mails(mb_id, &used);
printf("Before reset: used=%d\n", used);
/* 重置邮箱,清空所有邮件 */
os_mailbox_reset(mb_id);
os_mailbox_get_used_mails(mb_id, &used);
printf("After reset: used=%d\n", used); /* 输出 0 */
}📝 本节小结
邮箱是 OneOS 中高效的轻量级通信机制,关键要点:
- 传递指针值:邮箱传递
os_ubase_t类型的值,通常用于传递内存块指针或简单整数值 - 无数据拷贝:与消息队列不同,邮箱不拷贝数据,只拷贝指针值本身,效率更高
- 配套使用模式:发送方分配内存 → 发送指针 → 接收方处理 → 释放内存
- 静态和动态创建:两种方式都支持,静态创建使用
OS_MAILBOX_POOL_DEFINE定义邮件池 - 重置功能:
os_mailbox_reset可以清空邮箱中的所有邮件