1、邮箱
邮箱是线程间通信的一种方法,可以传递数据。
每封邮件4个字节大小(32 位CPU,指针的大小为 4 个字节,所以一封邮件恰好能够容纳一个指针)。
struct rt_mailbox
{
struct rt_ipc_object parent;
rt_uint32_t* msg_pool; /* 邮箱缓冲区的开始地址 */
rt_uint16_t size; /* 邮箱缓冲区的大小 */
rt_uint16_t entry; /* 邮箱中邮件的数目 */
rt_uint16_t in_offset, out_offset; /* 邮箱缓冲的进出指针 */
rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */
};
typedef struct rt_mailbox* rt_mailbox_t;
2、邮箱API
2.1、创建和删除邮箱
- 静态邮箱
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_IPC_FLAG_PRIO,即确保线程的实时性。 |
返回 | —— |
RT_EOK | 成功 |
rt_err_t rt_mb_detach(rt_mailbox_t mb);
参数 | 描述 |
---|---|
mb | 邮箱对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
- 动态邮箱
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_IPC_FLAG_PRIO,即确保线程的实时性。 |
返回 | —— |
RT_NULL | 创建失败 |
邮箱对象的句柄 | 创建成功 |
rt_err_t rt_mb_delete (rt_mailbox_t mb);
参数 | 描述 |
---|---|
mb | 邮箱对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
2.2、发送邮件
- 无等待发送邮件
无等待方式发送邮件,如果邮箱满了直接返回,不会造成阻塞
rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);
参数 | 描述 |
---|---|
mb | 邮箱对象的句柄 |
value | 邮件内容 |
返回 | —— |
RT_EOK | 发送成功 |
-RT_EFULL | 邮箱已经满了 |
- 等待发送邮件
rt_err_t rt_mb_send_wait (rt_mailbox_t mb,
rt_uint32_t value,
rt_int32_t timeout);
参数 | 描述 |
---|---|
mb | 邮箱对象的句柄 |
value | 邮件内容 |
timeout | 超时时间 |
返回 | —— |
RT_EOK | 发送成功 |
-RT_ETIMEOUT | 超时 |
-RT_ERROR | 失败,返回错误 |
- 发送紧急邮件
发送紧急邮件时,邮件被直接插到邮件队首,这样,接收者就能够优先接收到紧急邮件,从而及时进行处理。
rt_err_t rt_mb_urgent (rt_mailbox_t mb, rt_ubase_t value);
参数 | 描述 |
---|---|
mb | 邮箱对象的句柄 |
value | 邮件内容 |
返回 | —— |
RT_EOK | 发送成功 |
-RT_EFULL | 邮箱已满 |
2.3、接收邮件
rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);
参数 | 描述 |
---|---|
mb | 邮箱对象的句柄 |
value | 邮件内容 |
timeout | 超时时间 |
返回 | —— |
RT_EOK | 接收成功 |
-RT_ETIMEOUT | 超时 |
-RT_ERROR | 失败,返回错误 |
3、官方例程
#include <rtthread.h>
#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);