消息队列是RT-Thread中另一种常用的进(线)程程间通信方式,消息队列是对邮箱的扩展。
消息队列能够接收来自线程或中断服务例程(ISR)中发出的不固定长度的消息,并把消息缓存在自己的内存空间中,而其他线程能够从消息队列的消息链表头读取相应的消息并进行对应的处理。
消息链表尾指向消息队列中最后一条可用的消息。
当线程或中断服务例程(ISR)往消息队列中发送消息的时候,系统会从空闲链表中取出一个空闲的消息框,然后将发送过来的消息,放入空闲的消息框中,然后把这个消息框链接到消息链表尾。
消息队列支持紧急消息的发送,当线程或中断服务例程(ISR)发送的消息是一个紧急消息的时候,系统会直接将这个紧急消息链接到消息链表头,这样子等待的线程就可以第一时间获得紧急的消息进行应急处理。
当消息队列已满的时候,也就是消息队列中没有空闲的消息框的时候,线程或中断服务例程(ISR)还继续往消息队列中发送消息的时候,它们发送的这个行为就会失败。

D:\GD32\CODE\RT-Thread Simulator 例程代码\rtthread_simulator_v0.1.0\rtconfig.h
#define RT_ALIGN_SIZE 4 // 说明在操作系统中,对内存进行操作的时候,是以4字节进行对齐的
在 RT-Thread 中,消息队列控制块 是 操作系统 用于 管理消息队列 的一个数据结构。
/* **消息队列控制块**结构体定义 */
struct rt_messagequeue
{
struct rt_ipc_object parent; /**< **继承自IPC对象基类**,包含:
- 等待队列(挂起的接收线程)
- 名称(调试用)
- 对象类型标志 */
void *msg_pool; /**< **消息池起始地址**(动态内存或静态数组),
* 存储实际消息数据的连续内存区域 */
rt_uint16_t msg_size; /**< **单个消息的大小**(单位:**字节**), 因为是以4字节进行对齐的,所以这个msg_size**最小的单位就是4**,所以如果把msg_size定义为1的话,系统会自动将msg_size改为4
* 消息队列支持可变长度消息,但需按此大小对齐 */ // 如果把msg_size定义为5的话,系统会自动将msg_size改为8
rt_uint16_t max_msgs; /**< **消息队列最大容量**(单位:**消息数量**), **max_msgs = sizeof(msg_pool)/{msg_size + 指针的大小(32位系统指针大小是4字节)}**
* 表示可存储的最大消息条数 */
rt_uint16_t entry; /**< **当前队列中的有效消息数量**,entry=0 表示空,entry=max_msgs 表示满 */
void *msg_queue_head; /**< **消息链表头指针**(指向**第一个待读取**的**消息节点**),用于管理消息的先进先出(FIFO)顺序 */
void *msg_queue_tail; /**< **消息链表尾指针**(指向**最后一个待读取**的**消息节点**),新消息从此处加入链表 */
void *msg_queue_free; /**< **空闲消息节点链表指针**(指向**消息队列**中**未被使用**的**消息框**),用于快速分配和回收消息内存块 */
};
typedef struct rt_messagequeue *rt_mq_t; // 消息队列对象指针类型
**// 定义静态消息队列**
struct rt_messagequeue static_mq;
**// 定义动态消息队列**
rt_mq_t dynamic_mq;
初始化与脱离(针对于静态消息队列)
**// 人为设置——————>系统改为
// 7——————>8
// 1——————>4** **决定了消息队列缓冲区为空的时候,多个线程等待接收消息的排列方式**
// **单个消息占用的字节数 最多可存放的消息数目 |**
**// 静态消息队列初始化 消息队列指针 消息队列名称 消息队列缓冲区 单个消息的大小 消息队列缓冲区的大小 消息队列标志位————————————> RT_IPC_FLAG_FIFO—————先进先出,先进入线程等待队列的线程将优先获得消息**
rt_err_t rt_mq_init(rt_mq_t mq, const char *name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag); // **|————>** **RT_IPC_FLAG_PRIO—————线程将按照优先级的方式排队等候消息,优先级高的线程将优先获得消息**
**// 通过这个函数,可以将静态消息队列,加入,系统的,对象管理器**
**// 静态消息队列脱离 消息队列指针**
rt_err_t rt_mq_detach(rt_mq_t mq); // **用于将静态消息队列从系统的,对象管理器,中移除**
创建与删除(针对于动态消息队列)
**// 单个消息占用的字节数
// 动态消息队列创建 消息队列名称 单个消息的大小 消息队列最大容量 消息队列标志位————> 1.RT_IPC_FLAG_FIFO** 2.**RT_IPC_FLAG_PRIO**
rt_mq_t rt_mq_create(const char *name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag);
// **创建成功之后**,得到 rt_mq_t dynamic_mq 的**指针**,**需要进行判断**一下,如果 dynamic_mq **不为 NULL**,那么说明**创建成功**了,那么接下来就可以**对新创建的**这个**动态消息队列**进行**操作**
**// 动态消息队列删除 消息队列指针**
rt_err_t rt_mq_delete(rt_mq_t mq); // **不再使用**这个**动态消息队列**的**时**候,用于**将动态消息队列从系统的,对象管理器,中移除,释放系统资源**
发送消息
线程和中断服务例程(ISR)都可以向指定的消息队列发送一条消息。消息会被复制到消息队列的缓冲区中,供接收线程读取。
**// 待发送消息的 实际发送消息
// 发送消息 消息队列指针 缓冲区指针 的字节数**
rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size); // 用户需确保**消息的字节长度size**不超过**消息队列**的 **msg_size(单个消息占用的字节数)
// 消息队列 接收到 消息 以后,会把 消息 放到 消息队列 的 尾部**
**// 待发送数据的 实际发送消息**
**// 发送紧急消息 消息队列指针 缓冲区指针 的字节数**
rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size);
**// 消息队列 接收到 消息 以后,会把 消息 放到 消息队列 的 头部 ,等候读取消息 的 线程,会 第一时间 读取到 这个 紧急消息 ,然后进行处理**
接收消息
从消息队列接收一条消息,并将数据复制到用户提供的缓冲区中。(从队列接收数据,队列空时可能阻塞,不可在中断中使用)
**// 要接收消息的 接收消息的 |————— RT_WAITING_FOREVER = -1:永久阻塞,直到队列有消息
// 接收消息 消息队列指针 缓冲区指针 缓冲区的大小 超时时间(单位:Tick)————————— 0:非阻塞模式,接收不到消息立即返回**
rt_err_t rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, rt_int32_t timeout); // **|**———— **>0:等待指定的Tick数**
**//** **需预分配足够内存 |**
**//** **必须 ≥ 消息队列的 msg_size (单个消息占用的字节数)
// 否则返回错误**