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);

相关文章
|
4月前
|
存储 应用服务中间件 定位技术
Nginx数据结构
Nginx数据结构
|
存储 JavaScript 应用服务中间件
《深入理解Nginx:模块开发与架构解析》一3.4 HTTP模块的数据结构
本节书摘来自华章出版社《深入理解Nginx:模块开发与架构解析》一书中的第3章,第3.4节,作者 陶辉,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1994 0
|
应用服务中间件 nginx C语言
|
1天前
|
缓存 前端开发 JavaScript
终极 Nginx 配置指南(全网最详细)
本文详细介绍了Nginx配置文件`nginx.conf`的基本结构及其优化方法。首先通过删除注释简化了原始配置,使其更易理解。接着,文章将`nginx.conf`分为全局块、events块和http块三部分进行详细解析,帮助读者更好地掌握其功能与配置。此外,还介绍了如何通过简单修改实现网站上线,并提供了Nginx的优化技巧,包括解决前端History模式下的404问题、配置反向代理、开启gzip压缩、设置维护页面、在同一IP上部署多个网站以及实现动静分离等。最后,附上了Nginx的基础命令,如安装、启动、重启和关闭等操作,方便读者实践应用。
137 77
终极 Nginx 配置指南(全网最详细)
|
1月前
|
应用服务中间件 nginx Docker
本地通过域名访问虚拟机上nginx的服务、搭建域名访问环境一(反向代理配置)
这篇文章介绍了如何通过域名在本地访问虚拟机上的nginx服务,包括创建nginx容器、修改配置文件、修改本地host文件以及进行访问测试的详细步骤。文章提供了具体的Docker命令来创建并配置nginx容器,展示了配置文件的修改示例,说明了如何在本地系统的hosts文件中添加虚拟机IP和自定义域名,以及如何通过浏览器进行测试访问。
本地通过域名访问虚拟机上nginx的服务、搭建域名访问环境一(反向代理配置)
|
13天前
|
应用服务中间件 nginx
一文搞定Nginx配置RTMP!
一文搞定Nginx配置RTMP!
50 3
|
14天前
|
Ubuntu 应用服务中间件 数据库
Nginx配置:阻止非国内IP地址访问的设置方法
此外,出于用户隐私和法律合规性的考虑,应慎重考虑阻止特定国家或地区IP地址的决策。在某些情况下,这可能被视为歧视性或违反当地法律。
32 2