RT-Thread之邮箱使用示例

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

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

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

一、邮箱API函数

1、邮箱的创建

  • 动态创建邮箱(推荐灵活场景)
rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
  • 静态创建邮箱
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位的任意格式数据,可以是一个整型值或者一个指向某块内存的指针

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

3、消息的接收

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

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

4、邮箱的脱离/删除

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

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

二、创建邮箱示例

1、创建邮箱

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、接收与发送消息

#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条


保持热爱,奔赴星海

posted @ 2025-10-26 10:35  比特向阳  阅读(2)  评论(0)    收藏  举报