文章目录
- 前言
- 一、邮箱的特性
- 二、邮箱操作函数
- 2.1 创建邮箱
- 创建动态邮箱
- 创建静态邮箱
- 2.2 删除邮箱
- 2.3 发邮件
- 2.4 取邮件
- 三、示例代码
- 总结
前言
RT-Thread是一个开源的实时嵌入式操作系统,广泛应用于各种嵌入式系统和物联网设备。在RT-Thread中,邮箱是一种常用的线程间通信机制,用于实现不同线程之间的消息传递。本教程将介绍如何在RT-Thread中使用邮箱,以便开发者更好地利用这一功能。
一、邮箱的特性
邮箱的本质是环形缓冲区:
邮箱中的每一封邮件,只能容纳 4 字节内容(对于 32 位系统,指针大小刚好为 4 字节);
- 邮件的发送通常是非阻塞的,线程、中断都可以发送邮件;也可使用阻塞方式发送;
- 邮件的接收通常是阻塞的,取决于邮箱中是否有邮件;
- 当一个线程向邮箱发送邮件时:
- 如果邮箱没满,就把数值写入邮箱中
- 如果邮箱满了:
- 发送线程可以直接返回RT_EFULL
- 也可以挂起一段时间,在挂起的期间,别的线程或中断服务程序读了邮箱,会唤醒挂起的线程。
- 当一个线程从邮箱接收邮件时:
- 如果邮箱不为空,就读取邮箱中的数值
- 如果邮箱为空:
- 接收线可以直接返回RT_ETIMOUT
- 也可以挂起一段时间,在挂起的期间,别的线程或中断服务程序写了邮箱,会唤醒挂起的线程。
二、邮箱操作函数
邮箱由邮箱控制块管理,由结构体 rt_mailbox 表示。
使用邮箱的流程:创建/初始化邮箱、发送邮件、接收邮件、删除/脱离邮箱
2.1 创建邮箱
创建动态邮箱
我们可以使用下面这个函数创建动态邮箱:
rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);
参数说明:
name 邮箱名称
size 邮箱容量
flag 邮箱采用的等待方式: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO
返回值 邮箱对象的句柄:成功,返回句柄,以后使用句柄来操作邮箱,RT_NULL:失败
创建静态邮箱
我们可以使用下面这个函数创建静态邮箱:
rt_err_t rt_mb_init(rt_mailbox_t mb,
const char* name,
void* msgpool,
rt_size_t size,
rt_uint8_t flag);
参数说明:
mb 邮箱对象的句柄
name 邮箱的名字
msgpool 缓冲区指针
size 邮箱容量
flag 邮箱采用的等待方式: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO
返回值 RT_EOK:成功
2.2 删除邮箱
我们可以使用下面这个函数删除rt_mb_create
函数创建的邮箱:
rt_err_t rt_mb_delete (rt_mailbox_t mb);
参数为邮箱的handle
我们可以使用下面这个函数删除rt_mb_init
创建的邮箱:
rt_err_t rt_mb_detach(rt_mailbox_t mb);
参数为邮箱的handle
他们的返回值为RT_ERROR
时,表示出错了
2.3 发邮件
- 我们可以使用下面这个函数来发送邮件:
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value);
参数1为邮箱的handle
参数2为要发送的值
- 我们可以使用下面这个函数来发送邮件,并等待一定的tick:
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
rt_ubase_t value,
rt_int32_t timeout);
参数1为邮箱的handle
参数2为要发送的值
参数3为等待的tick
- 我们可以使用下面这个函数来发送紧急邮件:
rt_err_t rt_mb_urgent (rt_mailbox_t mb, rt_ubase_t value);
参数1为邮箱的handle
参数2为要发送的值
2.4 取邮件
我们可以使用下面这个函数来收邮件:
rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);
参数1为邮箱的handle
参数2为存储的地址
参数3为等待时间
三、示例代码
#include <rtthread.h>
// 定义一个邮箱句柄
static rt_mailbox_t mailbox;
// 定义一个线程1
static void thread1_entry(void *parameter)
{
rt_uint32_t message = 123;
// 发送消息到邮箱
rt_mb_send(mailbox, &message, sizeof(message));
// 等待一段时间,模拟其他操作
rt_thread_delay(50);
}
// 定义一个线程2
static void thread2_entry(void *parameter)
{
rt_uint32_t message;
// 从邮箱接收消息
rt_mb_recv(mailbox, &message, RT_WAITING_FOREVER);
// 处理接收到的消息
rt_kprintf("Received message: %d\n", message);
}
int mailbox_example(void)
{
// 创建邮箱,设置邮箱大小为5,每个消息大小为4字节
mailbox = rt_mb_create("mbox", 5, RT_IPC_FLAG_FIFO);
if (mailbox == RT_NULL)
{
rt_kprintf("Failed to create mailbox!\n");
return -1;
}
// 创建线程1
rt_thread_t thread1 = rt_thread_create("t1", thread1_entry, RT_NULL, 512, 10, 10);
if (thread1 != RT_NULL)
{
rt_thread_startup(thread1);
}
// 创建线程2
rt_thread_t thread2 = rt_thread_create("t2", thread2_entry, RT_NULL, 512, 11, 10);
if (thread2 != RT_NULL)
{
rt_thread_startup(thread2);
}
// 等待线程执行完成
rt_thread_mdelay(100);
// 删除邮箱
rt_mb_delete(mailbox);
return 0;
}
// 在RT-Thread的初始化中调用示例函数
INIT_APP_EXPORT(mailbox_example);
总结
通过本教程,我们深入了解了在RT-Thread中如何有效地使用邮箱进行线程间通信。邮箱作为一种轻量级的消息传递机制,为开发者提供了一种灵活而高效的方式来实现不同线程之间的数据传递。通过合理地利用邮箱,我们能够在嵌入式系统和物联网设备中构建更为可靠和响应的应用程序。希望本教程能够帮助开发者更好地利用RT-Thread的功能,提升嵌入式系统的开发效率和性能。