RT-Thread —邮箱 学习笔记
目录
概述
消息队列的本质是链表:
- 空闲消息块链表:往队列里写入消息时,先从空闲链表中得到消息块;从 队列读出消息后,把消息块放入空闲链表
- 消息块头部链表:消息写入消息块后,该消息块被放到尾部;从队列里读 消息时,从头部读。
使用消息队列可以传递各类大小的消息,它使用
memcpy
的方式写入消息、读出消息。
如果我们只是传递很小的数据,比如一些数值,可以使用邮箱:它的效率更高。
邮箱的特性
邮箱的本质是环形缓冲区:
![](https://i-blog.csdnimg.cn/blog_migrate/525b9e0b5019a734d0570795ba6c2242.png)
- 邮箱中的每一封邮件,只能容纳 4 字节内容(对于 32 位系统,指针大小刚好为 4 字节);
- 邮件的发送通常是非阻塞的,线程、中断都可以发送邮件;也可使用阻塞方式发送;
- 邮件的接收通常是阻塞的,取决于邮箱中是否有邮件;
- 当一个线程向邮箱发送邮件时:
- 如果邮箱没满,就把数值写入邮箱中
- 如果邮箱满了:
a.发送线程可以直接返回-RT_EFULL
b.也可以挂起一段时间,在挂起的期间,别的线程或中断服务程序读了邮箱,会唤醒挂起的线程。
-
当一个线程从邮箱接收邮件时:
- 如果邮箱不为空,就读取邮箱中的数值
- 如果邮箱为空:
a.接收线可以直接返回-RT_ETIMOUT
b.也可以挂起一段时间,在挂起的期间,别的线程或中断服务程序写了邮箱,会唤醒挂起的线程。
邮箱操作函数
创建/初始化
邮箱的创建有两种方法:
- 动态分配内存:rt_mb_create() ,邮箱的内存在函数内部动态分配,分配的内存大小为邮件大小乘以邮箱容量
- 静态分配内存:rt_mb_init(),邮箱的内存事先分配好,比如可以是数组。
rt_mb_create()
函数原型如下:
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_mb_init()
函数原型如下:
rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name,
void* msgpool,rt_size_t size,t_uint8_t flag)
参数
|
说明
|
mb
|
邮箱对象的句柄
|
name
|
邮箱的名字
|
msgpool
|
缓冲区指针
|
size
|
邮箱容量
|
flag
|
邮箱采用的等待方式:
RT_IPC_FLAG_FIFO
或
RT_IPC_FLAG_PRIO
|
返回值
|
RT_EOK
:成功
|
删除/脱离
不再使用一个邮箱时:
- 删除它:rt_mb_delete(),只能删除使用 rt_mb_create()创建的邮箱
- 脱离它:rt_mb_detach(),只能脱离使用 rt_mb_init()初始化的邮箱
删除邮箱的函数为
rt_mb_delete()
,它会释放内存。原型如下:
rt_err_t rt_mb_delete (rt_mailbox_t mb);
删除邮箱时,如果有线程在等待该邮箱,则内核先唤醒这些线程(线程返回值是
-
RT_ERROR
),然后再释放邮箱使用的内存,最后删除邮箱对象。
脱离邮箱将使邮箱对象被从内核对象管理器中脱离。原型如下:
rt_err_t rt_mb_detach(rt_mailbox_t mb);
脱离消息邮箱时,如果有线程在等待该邮箱,则内核会先唤醒这些线程(线程返回值
是
- RT_ERROR
)。
发邮件
RT-Thread
有三个发送邮件的函数:
- rt_mb_send() 发送邮件
- rt_mb_send_wait() 等待方式发送邮件
- rt_mb_urgent() 发送紧急邮件
线程或者中断服务程序都可以通过往邮箱里写入邮件。
发送的邮件,可以是
32
位的任意格式数据,可以是一个整型值或者一个指向某块内
存的指针。
使用
rt_mq_send()
发送消息时,只有在邮箱有可用的空闲空间时,才能成功发送消息, 否则返回错误码(-RT_EFULL)
。
使用
rt_mq_send_wait()
发送消息时,如果邮箱没有可用的空闲空间,会根据
timeout参数等待,超时后才返回错误。
使用
rt_mq_urgent()
发送消息时,只有在邮箱有可用的空闲空间,它才会把邮件插在邮件队首,以便这个邮件能被第 1
时间读取。
发送邮件的函数原型如下:
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
:邮箱满了
|
收邮件
当邮箱有邮件时,使用收邮件函数,可以从邮箱接收邮件。
如果没有邮件,根据指定的
timeout
参数等待,直到超时结束。
函数原型如下:
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
:失败,返回错误
|