玩转RT-Thread系列教程--消息邮箱的使用
Posted Rb菌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转RT-Thread系列教程--消息邮箱的使用相关的知识,希望对你有一定的参考价值。
玩转RT-Thread系列教程(3)–消息邮箱的使用
一、什么是消息邮箱
邮箱服务是实时操作系统中一种典型的线程间通信方法。
RT-Thread 操作系统的邮箱用于线程间通信,特点是开销比较低,效率较高。邮箱中的每一封邮件只能容纳固定的 4 字节内容
(针对 32 位处理系统,指针的大小即为 4 个字节,所以一封邮件恰好能够容纳一个指针)。
通常来说,邮件收取过程可能是阻塞的,这取决于邮箱中是否有邮件,以及收取邮件时设置的超时时间。
1.发送邮件
当一个线程向邮箱发送邮件时,如果邮箱没满,将把邮件复制到邮箱中。如果邮箱已经满了,发送线程可以设置超时时间,
选择等待挂起或直接返回 - RT_EFULL。如果发送线程选择挂起等待,那么当邮箱中的邮件被收取而空出空间来时,等待挂起的发送线程将被唤醒继续发送。
2.接收邮件
当一个线程从邮箱中接收邮件时,如果邮箱是空的,接收线程可以选择是否等待挂起直到收到新的邮件而唤醒,或可以设置超时时间。
当达到设置的超时时间,邮箱依然未收到邮件时,这个选择超时等待的线程将被唤醒并返回 - RT_ETIMEOUT。如果邮箱中存在邮件,
那么接收线程将复制邮箱中的 4 个字节邮件到接收缓存中。
二、消息邮箱的使用
介绍完了消息邮箱,那么消息邮箱的使用场合是什么呢?邮箱是一种简单的线程间消息传递方式,特点是开销比较低,效率较高。邮箱具备一定的存储功能,能够缓存一定数量的邮件数。
接下来让我们用一段示例代码演示以下消息邮箱的使用:
1.功能设计
线程1会向线程2发送消息,线程2接收到消息存放到邮箱中并串口输出该消息,同时发送消息给线程1,线程1接收到消息存放到邮箱中并串口输出该消息。当运行完2次发送任务时,删除二者邮箱,并串口输出“Mailboxes demo finsh”。
2.代码设计
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
/* defined the LED0 pin: PB5 */
#define LED0_PIN GET_PIN(B, 5)
/* defined the LED1 pin: PE5 */
#define LED1_PIN GET_PIN(E, 5)
/* 邮箱控制块 */
static struct rt_mailbox mb1;
/* 用于放邮件的内存池 */
static char mb_pool1[128];
/* 邮箱控制块 */
static struct rt_mailbox mb2;
/* 用于放邮件的内存池 */
static char mb_pool2[128];
static rt_uint8_t thread2_stack[512]; //线程栈
static struct rt_thread static_thread; //线程控制块
static char mb_str1[] = "thread1 send information";
static char mb_str2[] = "thread2 send information";
int main(void)
{
/* set LED0 pin mode to output */
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
/* set LED1 pin mode to output */
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT_PULLUP);
}
//thread1
static void dynamic_entry(void *param)
{
char *str;
static rt_uint8_t cnt;
while (cnt < 2)
{
cnt++;
/* 发送 mb_str1 地址到邮箱中 */
rt_mb_send(&mb2, (rt_uint32_t)&mb_str1);
rt_kprintf("@thread1 send mb to thread2\\r\\n");
/* 从邮箱中收取邮件 */
if (rt_mb_recv(&mb1, (rt_ubase_t *)&str, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread1: get a mail from mailbox1, the content:%s\\r\\n", str);
rt_thread_mdelay(50);
}
rt_thread_mdelay(50);
}
/* 执行邮箱对象脱离 */
if(rt_mb_detach(&mb1) != RT_EOK)
rt_kprintf("mb1 detach fail\\r\\n");
}
//thread2
static void static_entry(void *param)
{
char *str;
static rt_uint8_t cnt;
while (cnt < 2)
{
cnt++;
/* 从邮箱中收取邮件 */
if (rt_mb_recv(&mb2, (rt_ubase_t *)&str, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread2: get a mail from mailbox2, the content:%s\\r\\n", str);
rt_thread_mdelay(50);
rt_kprintf("@thread2 send mb to thread1\\r\\n");
/* 发送 mb_str2 地址到邮箱中 */
rt_mb_send(&mb1, (rt_uint32_t)&mb_str2);
}
rt_thread_mdelay(50);
}
if(rt_mb_detach(&mb2) != RT_EOK)
rt_kprintf("mb2 detach fail\\r\\n");
rt_kprintf("Mailboxes demo finsh\\r\\n");
}
int MailBox_demo(void)
{
rt_err_t result1, result2;
/* 初始化一个 mailbox */
result1 = rt_mb_init(&mb1,
"mbt1", /* 名称是 mbt */
&mb_pool1[0], /* 邮箱用到的内存池是 mb_pool */
sizeof(mb_pool1) / 4, /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */
RT_IPC_FLAG_FIFO); /* 采用 FIFO 方式进行线程等待 */
if (result1 != RT_EOK)
{
rt_kprintf("init mailbox1 failed.\\r\\n");
return -1;
}
/* 初始化一个 mailbox */
result2 = rt_mb_init(&mb2,
"mbt2", /* 名称是 mbt */
&mb_pool2[0], /* 邮箱用到的内存池是 mb_pool */
sizeof(mb_pool2) / 4, /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */
RT_IPC_FLAG_FIFO); /* 采用 FIFO 方式进行线程等待 */
if (result2 != RT_EOK)
{
rt_kprintf("init mailbox2 failed.\\r\\n");
return -1;
}
//
static rt_thread_t thread_id = RT_NULL;
thread_id = rt_thread_create("thread1", //名称
dynamic_entry, //线程代码
RT_NULL, //参数
512, //栈大小
14, //优先级
20); //时间片
if (thread_id != RT_NULL)
rt_thread_startup(thread_id); //线程进入就绪态
else
rt_kprintf("dynamic_thread create failure\\r\\n");
//
rt_thread_init(&static_thread, //线程handle
"thread2", //线程名称
static_entry, //线程入口函数
RT_NULL, //线程入口参数
&thread2_stack[0], //线程栈地址
sizeof(thread2_stack), //线程栈大小
15, //线程优先级
10); //线程时间片
rt_thread_startup(&static_thread); //线程进入就绪态
return RT_EOK;
}
MSH_CMD_EXPORT(MailBox_demo, MailBox_demo);
3.编译、下载、查看结果
通过串口数据我们不难发现,消息邮箱的运行机制,一方发送一方接收。
以上是关于玩转RT-Thread系列教程--消息邮箱的使用的主要内容,如果未能解决你的问题,请参考以下文章