RT-Thread之邮箱使用示例

3.9k words

邮箱(Mailbox)是RT-Thread中高效的线程间通信机制,其核心特点是:

  • 传输固定尺寸数据:每条消息为4字节(32位系统),可传递整型或指针
  • 轻量级通信:比消息队列更节省内存,适用于小数据量场景
  • 优先级传递:支持紧急消息优先处理

典型应用场景: 在硬件中断服务中,通过rt_mb_send快速传递传感器状态字,消费线程解析后触发相应动作,避免中断长时间占用CPU资源。

一、邮箱API函数

1、邮箱的创建

  • 动态创建邮箱(推荐灵活场景)
1
rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
  • 静态创建邮箱
1
2
3
4
5
rt_err_t rt_mb_init(rt_mailbox_t mb,
const char *name,
void *msgpool,
rt_size_t size,
rt_uint8_t flag)

2、邮箱的发送

线程或者中断服务程序都可以通过往邮箱里写入邮件。发送的邮件,可以是32位的任意格式数据,可以是一个整型值或者一个指向某块内存的指针

  • 直接发送邮件:只有在邮箱有可用的空闲空间时,才能成功发送消息,否则返回错误。
1
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value)
  • 等待发送邮件:如果邮箱没有可用的空闲空间,会根据timeout参数等待,超时后才返回错误。
1
2
3
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
rt_ubase_t value,
rt_int32_t timeout)
  • 紧急发送邮件:只有在邮箱有可用的空闲空间,它才会把邮件插在邮件队首,以便这个邮件能被第1时间读取。
1
rt_err_t rt_mb_urgent(rt_mailbox_t mb, rt_ubase_t value)

3、消息的接收

当邮箱有邮件时,使用收邮件函数,可以从邮箱接收邮件。如果没有邮件,根据指定的timeout参数等待,直到超时结束。

1
rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)

4、邮箱的脱离/删除

删除或者脱离邮箱时,如果有线程在等待该邮箱,则内核先唤醒这些线程(线程返回值是RT_ERROR),然后再释放邮箱使用的内存,最后删除邮箱对象。

  • 删除使用 rt_mb_create()创建的队列
1
rt_err_t rt_mb_delete(rt_mailbox_t mb)
  • 脱离使用 rt_mb_init()初始化的队列
1
rt_err_t rt_mb_detach(rt_mailbox_t mb)

二、创建邮箱示例

1、创建邮箱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct rt_mailbox mb_static;	/* 邮箱句柄 */
uint8_t msgpool[48]; /* 邮箱静态内存池 */

/* 静态创建一个邮箱 */
rt_mb_init(
&mb_static, /* 邮箱对象的句柄 */
"mb_static_test", /* 邮箱对象名称 */
msgpool, /* 内存池指向 */
sizeof(msgpool) / 4, /* 邮箱中能容纳的邮件数量,每封邮件占四字节 */
RT_IPC_FLAG_FIFO /* 如果有多个线程等待,按照先来先得到的方法分配 */
);



rt_mailbox_t mb_dynamic; /* 邮箱句柄指针 */
/* 动态创建一个邮箱 */
mb_dynamic = rt_mb_create(
"mb_dynamic_test", /* 邮箱对象名称 */
12, /* 邮箱中能容纳的邮件数量,每封邮件占四字节 */
RT_IPC_FLAG_FIFO /* 如果有多个线程等待,按照先来先得到的方法分配 */
);

2、接收与发送消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "thread_task.h"
#include "main.h"
#include <stdio.h>
#include "rtthread.h"
#include <rthw.h>

/******************************************** 线程 1 ******************************************************/
#define THREAD_1_PRIORITY 4 /* 进程优先级 */
#define THREAD_1_STACK_SIZE 512 /* 进程栈空间大小 */
#define THREAD_1_TIMESLICE 10 /* 进程执行时间片个数 */
static struct rt_thread *thread_1_handle; /* 进程句柄 */

/******************************************** 线程 2 ******************************************************/
#define THREAD_2_PRIORITY 5 /* 进程优先级 */
#define THREAD_2_STACK_SIZE 512 /* 进程栈空间大小 */
#define THREAD_2_TIMESLICE 10 /* 进程执行时间片个数 */
static struct rt_thread *thread_2_handle; /* 进程句柄 */

rt_mailbox_t mb_dynamic; /* 邮箱句柄指针 */

/**
* @brief 线程1入口函数
* @param 无
* @retval 无
*/
void thread_1_entry(void* param)
{
uint32_t value = 0;
while(1)
{
rt_thread_delay(4000); /* 精准延时4000时间片 */

rt_mb_recv(mb_dynamic, &value, 0xffffffff);
HAL_GPIO_TogglePin(GPIOC, LED1_Pin);
}
}

/**
* @brief 线程2入口函数
* @param 无
* @retval 无
*/
void thread_2_entry(void* param)
{
while(1)
{
rt_mb_send_wait(mb_dynamic, (uint32_t)0x01, 0xffffffff);
HAL_GPIO_TogglePin(GPIOC, LED2_Pin);

rt_thread_delay(200);
}
}



/**
* @brief 动态创建线程任务并启动
* @param 无
* @retval 无
*/
void ThreadStart(void)
{
rt_base_t level = rt_hw_interrupt_disable();
/* 动态创建线程 */
thread_1_handle = rt_thread_create(
"thread_1", /* 线程句柄名称*/
thread_1_entry, /* 函数入口 */
RT_NULL, /* 入口函数参数 */
THREAD_1_STACK_SIZE, /* 线程栈大小 */
THREAD_1_PRIORITY, /* 线程优先级 */
THREAD_1_TIMESLICE /* 线程时间片大小 */
);


rt_thread_startup(thread_1_handle); /* 启动线程 */

thread_2_handle = rt_thread_create(
"thread_2", /* 线程句柄名称*/
thread_2_entry, /* 函数入口 */
RT_NULL, /* 入口函数参数 */
THREAD_2_STACK_SIZE, /* 线程栈大小 */
THREAD_2_PRIORITY, /* 线程优先级 */
THREAD_2_TIMESLICE /* 线程时间片大小 */
);

rt_thread_startup(thread_2_handle); /* 启动线程 */

/* 动态创建邮箱 */
mb_dynamic = rt_mb_create(
"mb_dynamic_test",
12,
RT_IPC_FLAG_FIFO
);


rt_hw_interrupt_enable(level);
}

执行流程如下

(1)初始阶段

  • 线程1立即阻塞等待消息(邮箱空)
  • 线程2开始高频发送(每200 ticks发送1次)

(2)邮箱填满阶段

  • 线程2发送12条消息后邮箱满 → rt_mb_send_wait()开始阻塞

  • 系统进入双阻塞状态(线程1和2均挂起)

(3)恢复同步阶段

  • 线程1的rt_thread_delay(4000)到期后:

    • 消费1条消息 → 释放1个邮箱槽位

    • 唤醒线程2继续发送

  • 稳定状态:每4000 ticks消费1条,线程2每200 ticks补充1条