RT-Thread的消息队列

1.消息队列控制块的组成(结构体)
通过下图可以很容易发现消息队列有8个元素.msg_pool、.msg_size、max_msgs、.entry、.msg_queue_head、.msg_queue_tail、.msg_queue_free和.parent,其中.msg_pool为消息队列的起始地址;.msg_size为每条消息的大小;.max_msgs为消息队列的条目数;.entry队列内的消息索引;.msg_queue_head链表头; .msg_queue_tail链表尾; .msg_queue_free指向消息队列空闲节点;.parent.suspend_thread为获取消息而挂起的线程链表(线程控制块.tlist元素根据线程的状态被挂接在不同的链表中——比如就绪表、挂起表等)。
RT-Thread的消息队列_第1张图片
图1 消息队列结构体成员

/**
 * 消息队列结构体
 */
struct rt_messagequeue
{
    struct rt_ipc_object parent;                        /** 继承自ipc_object */

    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;                /** 指向消息队列空闲节点 */
};

/**
 * IPC object对象结构体
 */
struct rt_ipc_object
{
    struct rt_object parent;                            /** 继承自rt_object */

    rt_list_t        suspend_thread;                    /** 等待此资源的线程 */
};


/**
 * object对象结构体
 */
struct rt_object
{
    char       name[RT_NAME_MAX];                       /** 内核对象名 */
    rt_uint8_t type;                                    /** 内核对象类型 */
    rt_uint8_t flag;                                    /** 内核对象标志 */

    rt_list_t  list;                                    /** 内核对象链表节点 */
};

2.IPC对象的操作:
这里IPC对象包括信号量、互斥量、事件标志组、消息邮箱和消息队列,将共享以下操作。
2.1初始化IPC对象
IPC对象成员.suspend_thread是一个双向链表指针,用于为等待IPC对象的线程构建一条挂起线程链表。
RT-Thread的消息队列_第2张图片
图2.1-1 IPC对象初始化
RT-Thread的消息队列_第3张图片
图2.1-2 等待IPC对象挂起链表
2.2因等待IPC对象而挂起线程——RT-Thread提供了两种挂起线程机制。
2.2.1按先进先出方式挂起线程,这个比较好理解,等待IPC对象的线程按照程序执行的先后顺序挂在链表当中——当等待的资源(IPC对象)到来时,最先进入等待IPC对象的线程优先获得资源。
2.2.2按等待线程的优先级挂起线程,等待IPC对象的线程按照优先级高低挂在链表当中——当等待的资源(IPC对象)到来时,等待IPC对象优先级最高的线程优先获得资源。
2.3恢复等待IPC对象的线程,当等待的IPC对象到来,线程便从挂起态进入就绪态,这里的操作就是把xx.parent.suspend_thread->next指向的线程从中删除,然后再将线程控制块的tlist节点挂接到就绪表当中。

3.消息队列
3.1消息队列初始化
3.1.1将消息队列对象挂接到对象容器中,并设置消息队列对象的标志为RT_IPC_FLAG_FIFO或RT_IPC_FLAG_PRIO,用来设置等待消息队列对象的线程的挂起顺序。
RT-Thread的消息队列_第4张图片
图3.1-1 挂接消息队列对象到对象容器中

3.1.2初始化IPC对象;
3.1.3设置存储消息缓冲区的起始地址及消息的大小,并计算出内存池能存放多少条消息;
3.1.4初始化消息队列对象元素头、尾指针及空闲指针;
3.1.5将max_msgs条消息组成一条空闲链表。
RT-Thread的消息队列_第5张图片
图3.1-2 消息队列的初始状态
3.2从资源管理器中解依附消息队列对象
3.2.1恢复等待消息队列的所有线程,将所有挂起的线程恢复到就绪态;
3.2.2将消息队列对象从对象容器的消息队列链表中删除(只删除此节点)。
3.3向消息队列对象发送普通消息
3.3.1从空闲链表当中取出首节点;
RT-Thread的消息队列_第6张图片
图3.3-1 取出空闲链表的首节点
3.3.2将消息复制到msg指向的地址空间;
3.3.3将msg消息插入msg_queue_tail链表(如果msg_queue_head指向空地址,msg_queue_head也将指向msg消息),并增加消息的条目数;
RT-Thread的消息队列_第7张图片
图3.3-2 向尾部链表插入一条消息
3.3.4恢复因等待消息队列而挂起的线程,然后进行调度。
3.4向消息队列对象发送紧急消息
3.4.1从空闲链表当中取出首节点;
3.4.2将msg消息插入msg_queue_head链表(如果msg_queue_tail指向空地址,msg_queue_tail也将指向msg消息),并增加消息的条目数;
RT-Thread的消息队列_第8张图片
图3.4-1 向尾部链表插入一条消息
3.4.3恢复因等待消息队列而挂起的线程,然后进行调度。
3.5从消息队列对象获取消息
3.5.1取出当前线程句柄;
3.5.2若消息队列中没有消息,1)若不等待则直接返回;2)否则按照消息队列对象定义的方式(按先进先出方式或者按线程优先级方式)挂起当前线程;3)复位当前线程定时器并重新启动;4)进行调度;5)恢复到当线程,重新计算超时时间是否到达,没到则重复上述步聚,超时时间到则往下执行;
3.5.3从消息队列头部链表取出一条消息,并移动消息队列头部指针;
RT-Thread的消息队列_第9张图片
图3.5-1 从头部链表取出一条消息
3.5.4把取出的消息复制到消息缓冲区中;
3.5.5把消息指针挂接到消息队列空闲链表当中。
RT-Thread的消息队列_第10张图片
图3.5-2 把msg消息指针挂接到空闲链表中

你可能感兴趣的:(RT-Thread的消息队列)