消息队列

概述

XWOS的消息队列(xwmq)采用双循环链表实现。

flowchart LR
    Head --> Msg1 --> Head
    Msg1 --> Msg2 --> Msg1
    Msg2 --> Msg3 --> Msg2
    Msg3 --> Msg4 --> Msg3
    Msg4 --> Msg5 --> Msg4
    Msg5 --> Msg6 --> Msg5
    Msg6 --> Msg7 --> Msg6
    Msg7 --> Head --> Msg7

消息可发送到队列的头部,也可以发送到队列的尾部。 消息可以从队列的头部接收,也可以从队列的尾部接收。

消息队列的消息

消息队列的每个节点是 struct xwmq_msg

struct xwmq_msg {
        void * data;
        xwsq_t topic;
        struct xwlib_bclst_node node;
};
  • data :消息的数据,只能传递一个指针长度的数据
  • topic :消息的主题,由用户自定义主题的含义
  • node :链表节点

消息槽

消息槽 是消息队列初始化时,用户定义的消息数组。消息队列中的消息数量最多等于消息槽的数量。

消息队列对象与对象描述符描述符

消息队列对象是 XWOS对象 struct xwos_object 的派生类 。 类似的,消息队列对象也用 消息队列对象描述符 xwmq_d 来解决有效性和身份合法性的问题。

消息队列对象描述符由 消息队列对象的指针标签 组成:

typedef struct {
        struct xwmq * mq; /**< 消息队列对象的指针 */
        xwsq_t tik; /**< 标签 */
} xwmq_d;

通过对象描述符引用对象时,首先检测 obj->magic 的值,是否为 0x58574F53U ,由此可确定指针 obj 指向一个有效的 XWOS的对象 。 然后对比标签 obj->tiktik 是否相等,由此可以确定对象的 身份 。 因为对象的 tik 是全局唯一的,当对象被释放后,它的 tik 会被析构函数析构为 0 。 当内存地址被重新构建为新的对象,那么它的 tik 一定与对象描述符的 tik 不一致。

局限性

消息队列的消息只能发送一个和指针长度一样的数据。 如果需要发送比较大的数据,只能将数据的缓冲区的首地址发送出去。 若数据缓冲区是通过向动态内存管理申请而来,用户需要特别小心,数据缓冲区不能被意外地释放掉。

消息队列的静态初始化、销毁

  • 静态初始化: xwmq_init()
    • 静态 是指用户预先定义线程结构体对象,这些对象在编译期由编译器分配内存。
    • 初始化消息队列时,需要预先定义消息数组作为消息槽。
struct xwmq brd_mq;
struct xwmq_msg brd_mq_txq[16]; // 最多16个消息


xwer_t brd_init_xwmq(void)
{
        return xwmq_init(&brd_mq, brd_mq_txq, xw_array_size(brd_mq_txq));
}

消息队列的动态创建、删除

XWOS并未提供基于动态内存管理的创建与删除CAPI。

发送消息

入队

入队 是指将消息发送到消息队列的 尾端 ,发送之前需要获取一个可用的消息槽。

  • xwmq_eq() :等待消息槽,只能在 线程 上下文使用
  • xwmq_eq_to() :限时等待消息槽,只能在 线程 上下文使用
  • xwmq_eq_unintr() :不可中断地等待消息槽,只能在 线程 上下文使用
  • xwmq_tryeq() :尝试获取消息槽,可在 任意 上下文使用

插队

插队 是指将消息发送到消息队列的 首端 ,发送之前需要获取一个可用的消息槽。

  • xwmq_jq() :等待消息槽,只能在 线程 上下文使用
  • xwmq_jq_to() :限时等待消息槽,只能在 线程 上下文使用
  • xwmq_jq_unintr() :不可中断地等待消息槽,只能在 线程 上下文使用
  • xwmq_tryjq() :尝试获取消息槽,可在 任意 上下文使用

接收消息

首端离队

首端离队 是指从消息队列的 首端 接收消息。接收之后会释放一个消息槽。如果有发送线程正在等待消息槽,将唤醒发送线程。

  • xwmq_dq() :等待消息,只能在 线程 上下文使用
  • xwmq_dq_to() :限时等待消息,只能在 线程 上下文使用
  • xwmq_dq_unintr() :不可中断地等待消息,只能在 线程 上下文使用
  • xwmq_trydq() :尝试获取消息,可在 任意 上下文使用

尾端离队

尾端离队 是指从消息队列的 尾端 接收消息。接收之后会释放一个消息槽。如果有发送线程正在等待消息槽,将唤醒发送线程。

  • xwmq_rq() :等待消息,只能在 线程 上下文使用
  • xwmq_rq_to() :限时等待消息,只能在 线程 上下文使用
  • xwmq_rq_unintr() :不可中断地等待消息,只能在 线程 上下文使用
  • xwmq_tryrq() :尝试获取消息,可在 任意 上下文使用

消息队列对象的生命周期管理

消息队列对象的基类是 XWOS对象 struct xwos_object 。 消息队列对象也有两组生命周期管理的CAPI:

  • 使用 对象指针 访问生命周期管理的CAPI:需要确保调用CAPI时,对象一定是有效的,且不存在 释放-又被申请 为另一个对象的情况。

    • xwmq_grab() :增加引用计数。
    • xwmq_put() :减少引用计数,当引用计数减少为 0 时,调用垃圾回收函数释放对象。
  • 使用 对象描述符 访问生命周期管理的CAPI:用户无法确保对象一定有效或无法确保对象不会变成另一个对象时使用。

    • xwmq_acquire() :通过对象描述符确定对象有效且合法,再增加引用计数。
    • xwmq_release() :通过对象描述符确定对象有效且合法,再减少引用计数。 当引用计数减少为 0 时,调用垃圾回收函数释放对象。

CAPI参考