循环队列

概述

XWOS的循环队列(xwcq)是由 NUM 个大小为 SIZE 的数据缓冲区组成的队列。 这些缓冲区首尾相连,形成一个环。

pie
    title 循环队列
    "数据缓冲区0" : 1
    "数据缓冲区1" : 1
    "数据缓冲区2" : 1
    "数据缓冲区3" : 1
    "数据缓冲区4" : 1
    "数据缓冲区5" : 1
    "数据缓冲区6" : 1
    "数据缓冲区7" : 1

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

循环队列对象与对象描述符描述符

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

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

typedef struct {
        struct xwcq * cq; /**< 循环队列对象的指针 */
        xwsq_t tik; /**< 标签 */
} xwcq_d;

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

局限性

循环队列有自己数据缓冲区,用户的消息会被拷贝到数据缓冲区内,用户不必额外申请动态内存。 但循环队列缓冲区大小是固定的,用户只能发送小于等于缓冲区大小的数据。

循环队列的静态初始化、销毁

  • 静态初始化: xwcq_init()
    • 静态 是指用户预先定义线程结构体对象,这些对象在编译期由编译器分配内存。
    • 初始化循环队列时,需要预先定义数据缓冲区。
#define BRDCQ_SIZE 64
#define BRDCQ_NUM  8
XWCQ_DEF_MEMPOOL(brdcq_mempool, BRDCQ_SIZE, BRDCQ_NUM);
struct xwcq brdcq;

xwer_t brd_init_xwcq(void)
{
        return xwcq_init(&brdcq, BRDCQ_SIZE, BRDCQ_NUM, brdcq_mempool);
}

循环队列的动态创建、删除

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

发送消息

入队

入队 是指将消息发送到循环队列的 尾端 。 如果循环队列数据已被填满,循环队列会循环回队列 首端 的位置,覆盖掉原数据。

插队

插队 是指将消息发送到循环队列的 首端 。 如果循环队列数据已被填满,循环队列会循环回队列 尾端 的位置,覆盖掉原数据。

接收消息

接收消息 是指从循环队列中 取走 消息,消息取走后不再存在于循环队列。

首端接收

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

尾端离队

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

拷贝消息

拷贝消息 是指从循环队列中 拷贝 消息,不会从循环队列中删除消息。

首端拷贝

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

尾端拷贝

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

清空循环队列

用户可以通过 xwcq_flush() 将循环队列恢复到初始化状态。

获取循环队列容量

用户可以通过 xwcq_get_capacity() 获取循环队列的容量。 循环队列的容量是指数据缓冲区中数据槽的数量,也即是 xwcq_init() 的第三个参数。

获取循环队列单个数据槽的大小

用户可以通过 xwcq_get_size() 获取单个数据槽的大小。 也即是 xwcq_init() 的第二个参数。

获取循环队列中有效数据槽的数量

用户可以通过 xwcq_get_availability() 获取循环队列中有效数据槽的数量。 有效数据槽是指包含了可被接收数据的数据槽。

循环队列对象的生命周期管理

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

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

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

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

CAPI参考