簡介
- 郵箱是用來傳輸郵件的,如果沒人取件,會暫存下來。
- RT-Thread的郵箱,傳遞的是一個4位元組(32位)值,可以傳值,可以傳指針(32位MCU,指針為32位)。
- 郵箱使用比消息隊列更精簡,簡單的指令的傳輸,可以使用郵箱,資源占用可以更小。
相關API
- 在rt-thread核心代碼:
中,可以找到郵箱的各個APIrtthread.h
- 郵箱API的實作,在:
,可以認為郵箱屬于線程間通信的一種。ipc.c
- 郵箱:mailbox相關API如下
rt_mb_init \ rt_mb_detach :靜态初始化 \ 脫離,成對使用。
rt_mb_create \ rt_mb_delete : 動态建立 \ 删除,成對使用。
一般郵箱初始化後,就不再删除,可以使用靜态初始化的方式。
rt_mb_send : 發送郵件,可以工作在線上程、回調函數裡
rt_mb_send_wait :有逾時的發送,工作線上程
rt_mb_recv :等待接收郵件,注意是隊列式的接收,工作線上程裡,循環等待接收
rt_mb_control : 提供一個初始化RESET郵箱的指令,不常用。
- 開來,郵箱的API,跟消息隊列很相似。
測試執行個體
- 本例程用于線程間的通信,郵箱的消息,采用結構體指針。結構體的資料,動态申請記憶體的方式。
- 注意郵箱接收,需要判斷傳回值是否
,如下:== RT_EOK
/* 因為反正RT_EOK時為:0, 是以if判斷時,需要 == RT_EOK。否則接收正确後,if不成立 */
if (rt_mq_recv(&t3_mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK)
- 用于驗證郵箱傳輸是否正常,用于驗證記憶體的申請與釋放是否成對。
#include <rtthread.h>
/* 定義靜态全局的郵箱:非指針 */
static struct rt_mailbox t1_mb;
static struct rt_mailbox t2_mb;
static struct rt_mailbox t3_mb;
/* 郵箱的大小(池子):一般一個消息為4個位元組,這裡采用數組 */
static rt_uint8_t msg_buf1[128];
static rt_uint8_t msg_buf2[128];
static rt_uint8_t msg_buf3[128];
/* 測試線程 */
#define THREAD1_STACK_SIZE 1024
#define THREAD1_PRIORITY 20
#define THREAD1_TIMESLICE 10
#define THREAD2_STACK_SIZE 1024
#define THREAD2_PRIORITY 20
#define THREAD2_TIMESLICE 10
#define THREAD3_STACK_SIZE 1024
#define THREAD3_PRIORITY 20
#define THREAD3_TIMESLICE 10
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;
extern void list_mem(void);
/* 測試傳輸的資料 */
struct mb_msg
{
rt_uint8_t *data_ptr;
rt_uint32_t data_size;
};
/* 郵箱初始化,使用前需要初始化 */
static void mb_init(void)
{
rt_err_t result;
/* 初始化郵箱1 */
result = rt_mb_init(&t1_mb,
"t1mb",
&msg_buf1[0], /* 記憶體池指向 msg_pool */
sizeof(msg_buf1) / 4, /* 郵箱中的郵件數目,一封郵件占用4位元組 */
RT_IPC_FLAG_FIFO); /* 采用FIFO方式進行線程等待 */
if (result != RT_EOK)
{
rt_kprintf("init thread1 mailbox failed.\n");
return;
}
/* 初始化郵箱2 */
result = rt_mb_init(&t2_mb,
"t2mb",
&msg_buf2[0], /* 記憶體池指向 msg_pool */
sizeof(msg_buf2) / 4, /* 郵箱中的郵件數目,一封郵件占用4位元組 */
RT_IPC_FLAG_FIFO); /* 采用FIFO方式進行線程等待 */
if (result != RT_EOK)
{
rt_kprintf("init thread2 mailbox failed.\n");
return;
}
/* 初始化郵箱3 */
result = rt_mb_init(&t3_mb,
"t3mb",
&msg_buf3[0], /* 記憶體池指向 msg_pool */
sizeof(msg_buf3) / 4, /* 郵箱中的郵件數目,一封郵件占用4位元組 */
RT_IPC_FLAG_FIFO); /* 采用FIFO方式進行線程等待 */
if (result != RT_EOK)
{
rt_kprintf("init thread3 mailbox failed.\n");
return;
}
rt_kprintf("mb_init ok.\n");
}
/* 郵箱測試線程,按次序收與發 */
static void thread1_entry(void *param)
{
struct mb_msg *msg_recv_ptr1;
struct mb_msg *msg_send_ptr1;
char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
while(1)
{
if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr1->data_ptr);
list_mem();
rt_free(msg_recv_ptr1);
list_mem();
rt_thread_mdelay(500);
msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
msg_send_ptr1->data_size = sizeof(sbuf);
msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
}
}
}
static void thread2_entry(void *param)
{
struct mb_msg *msg_recv_ptr2;
struct mb_msg *msg_send_ptr2;
char sbuf[6] = {'T', 'a', 's', 'k', '2', '.'};
while(1)
{
if (rt_mb_recv(&t2_mb, (rt_ubase_t *)&msg_recv_ptr2, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 2:[recv=%s], print 2.\n", msg_recv_ptr2->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr2->data_ptr);
list_mem();
rt_free(msg_recv_ptr2);
list_mem();
rt_thread_mdelay(500);
msg_send_ptr2 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
msg_send_ptr2->data_size = sizeof(sbuf);
msg_send_ptr2->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr2->data_size);
rt_memcpy(msg_send_ptr2->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 2:[send=%s]\n", msg_send_ptr2->data_ptr);
rt_mb_send(&t3_mb, (rt_uint32_t)msg_send_ptr2);
}
}
}
static void thread3_entry(void *param)
{
struct mb_msg *msg_recv_ptr3;
struct mb_msg *msg_send_ptr3;
char sbuf[6] = {'T', 'a', 's', 'k', '3', '.'};
while(1)
{
if (rt_mb_recv(&t3_mb, (rt_ubase_t *)&msg_recv_ptr3, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 3:[recv=%s], print 3.\n", msg_recv_ptr3->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr3->data_ptr);
list_mem();
rt_free(msg_recv_ptr3);
list_mem();
rt_thread_mdelay(500);
msg_send_ptr3 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
msg_send_ptr3->data_size = sizeof(sbuf);
msg_send_ptr3->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr3->data_size);
rt_memcpy(msg_send_ptr3->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 3:[send=%s]\n", msg_send_ptr3->data_ptr);
rt_mb_send(&t1_mb, (rt_uint32_t)msg_send_ptr3);
}
}
}
/* 初始化并啟動郵箱的測試線程 */
static void task_init(void)
{
struct mb_msg *msg_send_ptr;
char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
rt_kprintf("%s: init start!\n", __func__);
list_mem();
rt_kprintf("%s: init end!\n", __func__);
tid1 = rt_thread_create("task1",
thread1_entry,
RT_NULL,
THREAD1_STACK_SIZE,
THREAD1_PRIORITY,
THREAD1_TIMESLICE);
tid2 = rt_thread_create("task2",
thread2_entry,
RT_NULL,
THREAD2_STACK_SIZE,
THREAD2_PRIORITY,
THREAD2_TIMESLICE);
tid3 = rt_thread_create("task3",
thread3_entry,
RT_NULL,
THREAD3_STACK_SIZE,
THREAD3_PRIORITY,
THREAD3_TIMESLICE);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
if (tid3 != RT_NULL)
rt_thread_startup(tid3);
rt_thread_mdelay(500);
msg_send_ptr = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
rt_kprintf("%s: rt_malloc 01\n", __func__);
list_mem();
rt_kprintf("%s: rt_malloc 01 end\n", __func__);
msg_send_ptr->data_size = sizeof(sbuf);
msg_send_ptr->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr->data_size);
rt_kprintf("%s: rt_malloc 02", __func__);
list_mem();
rt_kprintf("%s: rt_malloc 02 end\n", __func__);
rt_memcpy(msg_send_ptr->data_ptr, sbuf, sizeof(sbuf));
rt_mb_send(&t1_mb, (rt_uint32_t)msg_send_ptr);
rt_kprintf("task_init ok.\n");
}
/* MSH指令:啟動郵箱測試例程 */
int mb_test(void)
{
mb_init();
task_init();
return 1;
}
MSH_CMD_EXPORT(mb_test, mb test);
測試方法
- 序列槽輸入:
測試指令,啟動郵箱的測試mb_test
msh >mb_test
mb_init ok.
task_init: init start!
total memory: 89568
used memory : 10656
maximum allocated memory: 10656
task_init: init end!
task_init: rt_malloc 01
total memory: 89568
used memory : 14208
maximum allocated memory: 14208
task_init: rt_malloc 01 end
task_init: rt_malloc 02total memory: 89568
used memory : 14232
maximum allocated memory: 14232
task_init: rt_malloc 02 end
task_init ok.
msh >thread 1:[recv=Task1.###### ], print 1.
total memory: 89568
used memory : 14208
maximum allocated memory: 14232
total memory: 89568
used memory : 14184
maximum allocated memory: 14232
thread 1:[send=Task1.###### ]
thread 2:[recv=Task1.###### ], print 2.
total memory: 89568
used memory : 14208
maximum allocated memory: 14232
total memory: 89568
used memory : 14184
maximum allocated memory: 14232
thread 2:[send=Task2.###### ]
thread 3:[recv=Task2.###### ], print 3.
total memory: 89568
used memory : 14208
maximum allocated memory: 14232
total memory: 89568
used memory : 14184
maximum allocated memory: 14232
thread 3:[send=Task3.###### ]
thread 1:[recv=Task3.###### ], print 1.
total memory: 89568
used memory : 14208
maximum allocated memory: 14232
total memory: 89568
used memory : 14184
maximum allocated memory: 14232
thread 1:[send=Task1.###### ]
thread 2:[recv=Task1.###### ], print 2.
total memory: 89568
used memory : 14208
maximum allocated memory: 14232
total memory: 89568
used memory : 14184
- 說明郵箱已經正常的工作了。
總結
- 郵箱于消息隊列,都可以用于線程間的通信,相比消息隊列,郵箱本身更精簡。
- 郵箱的接收,類似于消息隊列,要放線上程,沒收到回suspend線程,是以可以使用:
RT_WAITING_FOREVER
- 熟練使用郵箱等線程間的通信,需要熟悉下核心代碼的實作,做的心中有數。