玩转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系列教程--消息邮箱的使用的主要内容,如果未能解决你的问题,请参考以下文章

玩转RT-Thread系列教程--消息队列的使用(串口DMA)

玩转RT-Thread系列教程(13)--MQTT协议通信

玩转RT-Thread系列教程(13)--MQTT协议通信

玩转RT-Thread系列教程文章资源汇总

玩转RT-Thread系列教程(10)--文件系统使用

玩转RT-Thread系列教程(10)--文件系统使用