RT-Thread 操作系统的邮箱用于线程间通信,特点是开销比较低,效率较高。邮箱中的每一封邮件只能容纳固定的4字节内容(针对32位处理器系统,指针大小即为4个字节,所以一封邮件恰好能够容纳一个指针)。
线程或ISP(中断服务程序)把一封4字节长度的邮件发送到邮箱中,而其他需要的线程可以从邮箱中接收这些邮件并进行处理。
struct rt_mailbox
{
struct rt_ipc_object parent; /**< inherit from ipc_object */
rt_ubase_t *msg_pool; /**< start address of message buffer */
rt_uint16_t size; /**< size of message pool */
rt_uint16_t entry; /**< index of messages in msg_pool */
rt_uint16_t in_offset; /**< input offset of the message buffer */
rt_uint16_t out_offset; /**< output offset of the message buffer */
rt_list_t suspend_sender_thread; /**< sender thread suspended on this mailbox */
};
typedef struct rt_mailbox *rt_mailbox_t;
rt_mailbox_t 是一个rt_mailbox 型的指针
成员 | 说明 |
---|---|
parent | 从系统IPC 对象继承 |
msg_pool | 邮箱中消息的缓存区起始地址 |
size | 邮箱大小 |
entry | 邮箱中邮件个数的指示 |
in_offset | 邮箱缓存区的进偏移量 |
out_offset | 邮箱缓存区的出偏移量 |
suspend_sender_thread | 挂起在邮箱上的发送线程(当邮箱已满,又想发送邮件的线程) |
(定义一个结构体)
struct rt_mailbox static_mb
(定义一个结构体指针)
rt_mailbox_t dynamic_mb
邮箱的初始化与脱离是针对静态邮箱的。
rt_err_t rt_mb_init(rt_mailbox_t mb,
const char *name,
void *msgpool,
rt_size_t size,
rt_uint8_t flag);
rt_err_t rt_mb_detach(rt_mailbox_t mb);
rt_mb_init
参数 | 说明 |
---|---|
mb | 邮箱控制块指针 |
name | 邮箱名称 |
msgpool | 邮箱缓存区地址 |
size | 邮箱大小 |
flag | 等候线程的排队方式(RT_IPC_FLAG_FIFO、RT_IPC_FLAG_PRIO) |
调用邮箱初始化或脱离API 就会分别将邮箱添加进系统管理器中或将邮箱从系统管理器中脱离。
邮箱的创建与删除是针对动态邮箱的。
rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag);
rt_err_t rt_mb_delete(rt_mailbox_t mb);
rt_mb_create
可见该API 相比静态邮箱的初始化API 缺少了mb、msgpool 参数,因为动态邮箱是根据邮箱大小在系统中申请一段动态内存,创建成功返回一个邮箱指针
参数 | 说明 |
---|---|
name | 邮箱名称 |
size | 邮箱大小 |
flag | 等候线程的排队方式(RT_IPC_FLAG_FIFO、RT_IPC_FLAG_PRIO) |
调用邮箱创建与删除API 就会分别创建邮箱进系统管理器中或将邮箱从系统管理器中移除。
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value);
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
rt_ubase_t value,
rt_int32_t timeout);
rt_mb_send
该函数本质上就是参数timeout 为零的rt_mb_send_wait
函数
参数 | 说明 |
---|---|
mb | 邮箱指针 |
value | 要发送的邮件内容 |
value 可以直接是要发送的邮件内容,也可以是邮件地址。
若邮箱已满,调用此函数将返回错误标志-RT_EFULL
rt_mb_send_wait
参数 | 说明 |
---|---|
mb | 邮箱指针 |
value | 邮件内容 |
timeout | 超时时间 |
value 可以直接是要发送的邮件内容,也可以是邮件地址。
若邮箱已满,则会根据timeout 进行相应时间等待。
rt_mb_send
函数(即timeout = 0的 rt_mb_send_wait
函数)可以在线程和中断中调用,当timeout 不为零时,rt_mb_send_wait
函数只能在线程中调用。
rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout);
参数 | 说明 |
---|---|
mb | 邮箱地址 |
value | 存储邮件的内存地址(注意:此处需要传入指针的取地址,见例程) |
timeout | 等待超时时间(当邮箱为空时) |
#define THREAD_PRIORITY 10
#define THREAD_TIMESLICE 5
/* 邮箱控制块 */
static struct rt_mailbox mb;
/* 用于放邮件的内存池 */
static char mb_pool[128];
static char mb_str1[] = "I'm a mail!";
static char mb_str2[] = "this is another mail!";
static char mb_str3[] = "over";
ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
/* 线程1入口 */
static void thread1_entry(void *parameter)
{
char *str;
while (1)
{
rt_kprintf("thread1: try to recv a mail\n");
/* 从邮箱中收取邮件 */
if (rt_mb_recv(&mb, (rt_uint32_t *)&str, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread1: get a mail from mailbox, the content:%s\n", str);
if (str == mb_str3)
break;
/* 延时100ms */
rt_thread_mdelay(100);
}
}
/* 执行邮箱对象脱离 */
rt_mb_detach(&mb);
}
ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 线程2入口 */
static void thread2_entry(void *parameter)
{
rt_uint8_t count;
count = 0;
while (count < 10)
{
count ++;
if (count & 0x1)
{
/* 发送mb_str1地址到邮箱中 */
rt_mb_send(&mb, (rt_uint32_t)&mb_str1);
}
else
{
/* 发送mb_str2地址到邮箱中 */
rt_mb_send(&mb, (rt_uint32_t)&mb_str2);
}
/* 延时200ms */
rt_thread_mdelay(200);
}
/* 发送邮件告诉线程1,线程2已经运行结束 */
rt_mb_send(&mb, (rt_uint32_t)&mb_str3);
}
int mailbox_sample(void)
{
rt_err_t result;
/* 初始化一个mailbox */
result = rt_mb_init(&mb,
"mbt", /* 名称是mbt */
&mb_pool[0], /* 邮箱用到的内存池是mb_pool */
sizeof(mb_pool) / 4, /* 邮箱中的邮件数目,因为一封邮件占4字节 */
RT_IPC_FLAG_FIFO); /* 采用FIFO方式进行线程等待 */
if (result != RT_EOK)
{
rt_kprintf("init mailbox failed.\n");
return -1;
}
rt_thread_init(&thread1,
"thread1",
thread1_entry,
RT_NULL,
&thread1_stack[0],
sizeof(thread1_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread2,
"thread2",
thread2_entry,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(mailbox_sample, mailbox sample);