《野火RT-Thread内核实现与应用开发实战》笔记8. 消息队列

1. 基本概念

队列又称消息队列,是一种常用于线程间通信的数据结构,队列可以在线程与线程间、中断和线程间传送信息,实现了线程接收来自其他线程或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在线程自己的空间。线程能够从队列里面读取消息,当队列中的消息是空时,挂起读取线程,用户还可以指定挂起的线程时间 timeout;当队列中有新消息时,挂起的读取线程被唤醒并处理新消息,消息队列是一种异步的通信方式。

通过消息队列服务,线程或中断服务例程可以将一条或多条消息放入消息队列中。同样,一个或多个线程可以从消息队列中获得消息。当有多个消息发送到消息队列时,通常是将先进入消息队列的消息先传给线程,也就是说,线程先得到的是最先进入消息队列的消息,即先进先出原则(FIFO)。同时 RT- Thread 中的消息队列支持优先级,也就是说在所有等待消息的线程中优先级最高的会先获得消息。

2. 运行机制

消息队列结构体:

struct rt_messagequeue
{
    struct rt_ipc_object parent;                       
    void                *msg_pool;                     
    rt_uint16_t          msg_size;                     
    rt_uint16_t          max_msgs;                     
    rt_uint16_t          entry;                        
    void                *msg_queue_head;                
    void                *msg_queue_tail;                
    void                *msg_queue_free;               
    rt_list_t            suspend_sender_thread;        
};
typedef struct rt_messagequeue *rt_mq_t;

消息链表结构体:

struct rt_mq_message
{
    struct rt_mq_message *next;
};

四个重要函数:

/**< 消息队列创建函数 */
rt_mq_t rt_mq_create(const char *name,
                     rt_size_t   msg_size,
                     rt_size_t   max_msgs,
                     rt_uint8_t  flag);
/**< 消息队列发送函数 */
rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size);
/**< 消息队列接收函数 */
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_delete(rt_mq_t mq);

消息队列从初始状态到被写入一条消息,再被写入一条消息,然后被读出一条消息,再被读出一条消息,这一过程消息队列结构体的成员是如何变化的呢?消息池是如何被使用的呢?下图展示了这一过程各变量的变化情况:
在这里插入图片描述

3. 阻塞机制

我们使用的消息队列一般不是属于某个线程的队列,在很多时候,我们创建的队列,是每个线程都可以去对他进行读写操作的,但是为了保护每个线程对它进行读写操作的过程,我们必须要有阻塞机制,在某个线程对它读写操作的时候,必须保证该线程能正常完成读写操作,而不受后来的线程干扰,凡事都有先来后到嘛!

那么,如何实现这个先来后到的机制呢,很简单,因为 RT-Thread 已经为我们做好了,我们直接使用就好了,每个对消息队列读写的函数,都有这种机制,我称之为阻塞机制。假设有一个线程A 对某个队列进行读操作的时候(也就是我们所说的出队),发现它没有消息,那么此时线程 A有 3 个选择 :

  • timeout=RT_WAITING_NO:宏RT_WAITING_NO为0,这种情况线程 A 扭头就走,既然队列没有消息,那我也不等了,干其它事情去,这样子线程 A 不会进入阻塞态。
  • timeout=RT_WAITING_FOREVER:这种情况线程 A 死等,不等到消息就不走了,这样子线程A 就会进入阻塞态,直到完成读取队列的消息。
  • timeout=n, n>0:这种情况线程 A 还是在这里等n 个 tick ,在这 n 个 tick 到来之前线程 A 都是处于阻塞态,当阻塞的这段时间线程 A 等到了队列的消息,那么线程 A 就会从阻塞态变成就绪态,如果此时线程 A比当前运行的线程优先级还高,那么,线程 A 就会得到消息并且运行;假如 n个 tick 都过去了,队列还没消息,那线程 A 就不等了,从阻塞态中唤醒,返回一个没等到消息的错误代码,然后继续执行线程 A 的其他代码。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值