Nginx 数据结构 ngx_queue_t

简介: ngx_queue_t不分配内存,只是将已分配好的内存用双向链表连接。 消耗内存少,虽太适合超大规模数据的排序,但胜在简单使用。 作为C语言提供的通用双向链表,其设计思路值得参考。 在理解设计的时候可以将其想象成环形结构。 typedef struct ngx_queue_s  ngx_queue_t; struct ngx_queue_s  {     ng
ngx_queue_t不分配内存,只是将已分配好的内存用双向链表连接。
消耗内存少,虽太适合超大规模数据的排序,但胜在简单使用。
作为C语言提供的通用双向链表,其设计思路值得参考。
在理解设计的时候可以将其想象成环形结构。


typedef struct ngx_queue_s  ngx_queue_t;

struct ngx_queue_s 
{
    ngx_queue_t* prev;
    ngx_queue_t* next;
};

比较迷惑的是该容器与其中的元素使用相同的结构体。


操作

#define ngx_queue_init(q)     \
    (q)->prev = q;            \
    (q)->next = q

初始化容器
当容器一端(prev/next)不含有元素的时候,指向容器本身。

#define ngx_queue_empty(h)    \
    (h == (h)->prev)

判断容器是否为空
如果容器与容器的prev相等,则容器不含任何元素

#define ngx_queue_insert_head(h, x)   \
    (x)->next = (h)->next;            \
    (x)->next->prev = x;              \
    (x)->prev = h;                    \
    (h)->next = x

在容器h头部插入元素x:

#define ngx_queue_insert_tail(h, x)   \
    (x)->prev = (h)->prev;            \
    (x)->prev->next = x;              \
    (x)->next = h;                    \
    (h)->prev = x

在容器h尾部添加元素x

void ngx_queue_sort(ngx_queue_t *queue, ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));

对容器进行排序,排序规则cmp要程序员自己实现。

#define ngx_queue_head(h)           \
    (h)->next

#define ngx_queue_last(h)          \
    (h)->prev

分别获取容器的头部元素和尾部元素。
第一眼看上去比较奇怪,取得头部的为何是(h)->next而不是(h)->prev呢?
看完下边的几个示意图就明白了。


// 有一个ngx_queue_t容器
ngx_queue_t gather;

// 使用ngx_queue_init初始化
ngx_queue_init(&gather);

// 容器中为空的时候情况:


// 容器中含有1个元素的情况:
// 在h头部插入x, ngx_queue_insert_head

原先: 
h->prev = h;
h->next = h;

过程:
x->next = h; // h->next的值为h
h->prev = x; // x->next的值为h
x->prev = h;
h->next = x;



// 容器中含有2个元素的情况:
// 在h头部再插入y, ngx_queue_insert_head
原先:
h->prev = x;
x->prev = h;
h->next = x;
x->next = h;

#define ngx_queue_insert_head(h, y)   \
    (y)->next = (h)->next;            \
    (y)->next->prev = y;              \
    (y)->prev = h;                    \
    (h)->next = y

过程:
y->next = x; // (h)->next的值为x
x->prev = y; // (y)->next的值为x
y->prev = h;
h->next = y;



// 容器中含有3个元素的情况:
// 在h尾部添加元素z, ngx_queue_insert_tail
原先:

h->next = y;
y->next = x;
x->next = h;

x->prev = y;
y->prev = h;
h->prev = x;

#define ngx_queue_insert_tail(h, z)   \
    (z)->prev = (h)->prev;            \
    (z)->prev->next = z;              \
    (z)->next = h;                    \
    (h)->prev = z

过程:

z->prev = x;
x->next = z;
z->next = h;
h->prev = z;



通过以上示意图可以看到,容器的prev总指向容器的最后一个元素,next总指向容器的第一个元素。
仿佛该容器是一个圆环,头尾头尾头尾相互咬合。


使用:(示例来自于《深入理解Nginx: 模块开发与架构解析》)

ngx_queue_t可以作为另一个结构体的成员,然后该结构体对象通过该成员链接到链表上。
ngx_queue_t成员位置随意。

// 以下示例创建一个容器,然后添加5个元素,最后排序

struct TestNode
{
     char* str;
     ngx_queue_t qt;
     int num;
};

// 排序函数,通过num排序
ngx_int_t cmp(const ngx_queue_t* a, const ngx_queue_t* b)
{
     // 通过ngx_queue_data获取结构体TestNode对象的地址
     TestNode* aNode = ngx_queue_data(a, TestNode, qt);
     TestNode* bNode = ngx_queue_data(a, TestNode, qt);
     return aNode->num > bNode->num;
}

// 遍历链表
void trav(ngx_queue_t* q)
{
     ngx_queue_t* idx;
     for(idx = ngx_queue_head(q);
         idx != ngx_quque_sentinel(q);
         idx = ngx_quque_next(idx))
     {
          TextNode* node = ngx_queue_data(idx, TestNode, qt);
          printf("num: %d\n", node->num);
     }
}

TestNode q;
TestNode nodes[5];
for(int i = 0; i < 5; ++i)
     nodes[i].num = 5;

ngx_queue_insert_tail(&q, &nodes[0].qt);
ngx_queue_insert_head(&q, &nodes[1].qt);
ngx_queue_insert_tail(&q, &nodes[2].qt);
ngx_queue_insert_head(&q, &nodes[3].qt);
ngx_queue_insert_tail(&q, &nodes[4].qt);

// 遍历输出
trav(&q);

// 排序
ngx_queue_sort(&q, cmp);

// 遍历输出
trav(&q);

相关文章
|
2月前
|
存储 应用服务中间件 nginx
nginx数据结构组件二
nginx数据结构组件二
27 0
|
2月前
|
存储 缓存 应用服务中间件
Nginx入门 -- 基本数据结构中之ngx_hash_t
Nginx入门 -- 基本数据结构中之ngx_hash_t
40 0
|
2月前
|
运维 监控 应用服务中间件
nginx基本数据结构 - ngx_queue_t使用举例
nginx基本数据结构 - ngx_queue_t使用举例
35 0
|
2月前
|
存储 缓存 应用服务中间件
Nginx入门 -- 基本数据结构中之ngx_list_t,ngx_queue_t
Nginx入门 -- 基本数据结构中之ngx_list_t,ngx_queue_t
30 0
|
2月前
|
存储 应用服务中间件 nginx
Nginx入门 -- 基本数据结构中之ngx_str_t,ngx_array_t
Nginx入门 -- 基本数据结构中之ngx_str_t,ngx_array_t
73 0
|
4月前
|
应用服务中间件 nginx 开发者
nginx基本数据结构 - ngx_queue_t使用举例
`ngx_queue_t`为Nginx提供了简单而强大的双向链表操作功能。其接口简洁,使用方便,适用于各种需要快速插入和删除元素的场景。在高并发的Nginx模块和其他代码中,`ngx_queue_t`提供了一种高效组织和管理数据的方法。通过对队列的高效操作,开发者可以极大地提升应用程序性能和稳定性,更好地处理并发数据流。
57 1
|
4月前
|
应用服务中间件 nginx C语言
Nginx入门 -- 基本数据结构中之ngx_str_t,ngx_array_t
这两种数据结构是Nginx自定义数据类型的例子,它们证明了Nginx设计者在构建一个为高并发和高性能优化的web服务器时的精确和高效。理解这些数据结构是深入学习Nginx内部机制的基础,同时也是扩展和开发Nginx模块不可或缺的一部分知识。
43 1
|
7月前
|
存储 应用服务中间件 定位技术
Nginx数据结构
Nginx数据结构
|
存储 JavaScript 应用服务中间件
《深入理解Nginx:模块开发与架构解析》一3.4 HTTP模块的数据结构
本节书摘来自华章出版社《深入理解Nginx:模块开发与架构解析》一书中的第3章,第3.4节,作者 陶辉,更多章节内容可以访问云栖社区“华章计算机”公众号查看
2021 0
|
应用服务中间件 nginx C语言