消息队列是一种线程间的通信方式,是邮箱的扩展
消息队列的工作机制
消息队列能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中。其他线程也能够从消息队列中读取相应的消息,而当消息队列为空时,可挂起读取线程。当有新的消息到达时,挂起的线程将被唤醒为接收并处理消息
消息队列是一种异步的通信方式
通常将先进入消息队列的消息先传给线程,线程先得到最先进入消息队列的消息,即先进先出原则(FIFO)
- 当消息队列被创建时,它就被分配了消息队列控制块:消息队列名称、内存缓冲区、消息大小、消息队列长度等;
- 每个消息队列对象包含多个消息框,每个消息框都存放一条消息;
- 消息队列的第一个和最后一个消息框分别称为消息队列头、消息队列尾,对应msg_queue_head msg_queue_tail
- 有些消息框可能是空的,通过msg_queue_free形成一个空闲消息框队列
消息队列相关接口
RT-thread提供了相关接口控制消息队列
消息队列创建/删除
创建消息队列
rt_mq_t rt_mq_create(const char *name,
rt_size_t msg_size,
rt_size_t max_msgs,
rt_uint8_t flag);
消息队列内存计算:
消息队列内容 = [ 消息队列头的大小+ 消息大小 ] x 消息队列长度
FLAG 中有两个选项,RT_ICP_FLAG_FIFO 为非实时调度方式,除非应用程序非常看重先来后到的顺序,否则推荐使用 RT_ICP_FLAG_PRIO,即确保实时准确性
删除消息队列
rt_err_t rt_mq_delete(rt_mq_t mq);
消息队列初始化/脱离
消息队列初始化
初始化消息队列用于静态消息队列对象的初始化,静态消息队列对象的内存是在系统编译时由编译器分配的
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_err_t rt_mq_detach(rt_mq_t mq);
消息队列发送
- 线程和中断程序都可以个給消息队列发送消息,当发送消息时,消息队列对象先从空闲的消息链表上取下一个空闲消息块,并将要发送的数据复制到空白的消息块中;
- 将该消息块方式到消息队列尾部
- 当且只当空闲链表有可用空闲消息块的时候,发送者才可以成功发送消息
- 当空闲消息块上无可用消息块时,及代表队列已满,此时发送消息的线程或中断程序会返回一个错误码(RT_EFULL)RT_EFULL
rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size);
消息队列阻塞式发送
- 阻塞式与非阻塞的区别为,当消息队列满的时候,那么发送线程将根据设定的timeout参数进行等待;
- 如果查过设置超时时间依然没有空出空间,这时线程将会唤醒并返回错误码
rt_err_t rt_mq_send_wait(rt_mq_t mq,
const void *buffer,
rt_size_t size,
rt_int32_t timeout)
消息队列接收
当消息队列中有消息时,接收者才可以接收消息,否则会根据超时时间设置,或挂起在消息队列的等待线程队列上,或直接返回
rt_err_t rt_mq_recv(rt_mq_t mq,
void *buffer,
rt_size_t size,
rt_int32_t timeout);
消息队列发送紧急消息
发送紧急消息的过程与发送消息几乎一样,唯一不同是,当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂在队首
rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size);