nginx之queue的具体使用


Posted in Servers onJune 28, 2022

一、简介

​ nginx队列和linux内核中的链表有一样的结构,只有一个连接头(只有两个指针),任何包含这个结构的数据都可以连接在一起。有点像物联网,万物互联,只要能上网都可以连接。

​ nginx队列是带头节点的一个双向链表。

二、数据结构

typedef struct ngx_queue_s  ngx_queue_t;

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

nginx之queue的具体使用

三、相关API

3.1 初始化一个队列

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

nginx之queue的具体使用

3.2 判断队列是否为空

只有一个头节点,则为空。有头节点的双向链表相比无头的双向链表,各种插入、删除等操作都更简单。

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

3.3 队头插入节点

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

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

头部插入节点后

nginx之queue的具体使用

3.4 队尾插入节点

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

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

尾部插入节点后

nginx之queue的具体使用

3.5 从队列中移除某个节点

#define ngx_queue_remove(x)                                                   \
    (x)->next->prev = (x)->prev;                                              \
    (x)->prev->next = (x)->next

nginx之queue的具体使用

nginx之queue的具体使用

移除x节点后

nginx之queue的具体使用

可以看到移除节点x后,x和队列还有一定的联系,所以对x的操作一定要小心,不然可能将整个队列损坏。 一般将x->prev,x->next都置空。

3.6 将队列从某个节点拆分成两个队列

#define ngx_queue_split(h, q, n)                                              \
    (n)->prev = (h)->prev;                                                    \
    (n)->prev->next = n;                                                      \
    (n)->next = q;                                                            \
    (h)->prev = (q)->prev;                                                    \
    (h)->prev->next = h;                                                      \
    (q)->prev = n;

将队列h从节点q拆分为h和n两个队列,并且q节点在n队列中。

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

拆分完后

nginx之queue的具体使用

3.7 将两个队列合并成一个队列

#define ngx_queue_add(h, n)                                                   \
    (h)->prev->next = (n)->next;                                              \
    (n)->next->prev = (h)->prev;                                              \
    (h)->prev = (n)->prev;                                                    \
    (h)->prev->next = h;

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

nginx之queue的具体使用

合并后

nginx之queue的具体使用

3.8 队列排序

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


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


#define ngx_queue_sentinel(h)                                                 \
    (h)


#define ngx_queue_next(q)                                                     \
    (q)->next


#define ngx_queue_prev(q)                                                     \
    (q)->prev
#define ngx_queue_insert_after ngx_queue_insert_head

使用标准的插入排序算法,通过传递的回调函数cmp进行比较,将整个队列排序。

void
ngx_queue_sort(ngx_queue_t *queue,
    ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
{
    ngx_queue_t  *q, *prev, *next;

    q = ngx_queue_head(queue);

    if (q == ngx_queue_last(queue)) {
        return;
    }

    for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {

        prev = ngx_queue_prev(q);
        next = ngx_queue_next(q);

        ngx_queue_remove(q);

        do {
            if (cmp(prev, q) <= 0) {
                break;
            }

            prev = ngx_queue_prev(prev);

        } while (prev != ngx_queue_sentinel(queue));

        ngx_queue_insert_after(prev, q);
    }
}

3.9 获取队列中间节点

通过快慢指针的方式获取中间节点。

ngx_queue_t *
ngx_queue_middle(ngx_queue_t *queue)
{
    ngx_queue_t  *middle, *next;

    middle = ngx_queue_head(queue);

    if (middle == ngx_queue_last(queue)) {
        return middle;
    }

    next = ngx_queue_head(queue);

    for ( ;; ) {
        middle = ngx_queue_next(middle);

        next = ngx_queue_next(next);

        if (next == ngx_queue_last(queue)) {
            return middle;
        }

        next = ngx_queue_next(next);

        if (next == ngx_queue_last(queue)) {
            return middle;
        }
    }
}

3.10 获取原始数据

#define ngx_queue_data(q, type, link)                                         \
    (type *) ((u_char *) q - offsetof(type, link))

从队列中获取的节点类型都是ngx_queue_s,而不是实际的数据类型,需要将ngx_queue_s转换为原始的类型。其中offsetof是一个内置的表达式,计算某个成员变量在类型中的偏移量。
通过偏移计算到计算到原始类型地址,然后进行类型强转获取原始类型。
比如如下调用

q = ngx_queue_last(&cache->expire_queue);
file = ngx_queue_data(q, ngx_cached_open_file_t, queue);

nginx之queue的具体使用

q的地址减去offset获取到ngx_cached_open_file_t的地址,然后在强转为对应的类型。

到此这篇关于nginx之queue的具体使用的文章就介绍到这了,更多相关nginx queue内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

Servers 相关文章推荐
Nginx搭建rtmp直播服务器实现代码
Mar 31 Servers
如何利用map实现Nginx允许多个域名跨域
Mar 31 Servers
Nginx反向代理及负载均衡如何实现(基于linux)
Mar 31 Servers
Nginx部署vue项目和配置代理的问题解析
Aug 04 Servers
Nginx location 和 proxy_pass路径配置问题小结
Sep 04 Servers
Nginx配置文件详解以及优化建议指南
Sep 15 Servers
CentOS安装Nginx并部署vue
Apr 12 Servers
Window server 2012 R2 AD域的组策略相关设置
Apr 28 Servers
nginx rewrite功能使用场景分析
May 30 Servers
shell进度条追踪指令执行时间的场景分析
Jun 16 Servers
Nginx开源可视化配置工具NginxConfig使用教程
Jun 21 Servers
Zabbix对Kafka topic积压数据监控的问题(bug优化)
Jul 07 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
PHP中函数内引用全局变量的方法
2008/10/20 PHP
php设计模式之单例模式代码
2016/06/11 PHP
PHP实现基于3DES算法加密解密字符串示例
2018/08/24 PHP
javascript flash下fromCharCode和charCodeAt方法使用说明
2008/01/12 Javascript
获取服务器传来的数据 用JS去空格的正则表达式
2012/03/26 Javascript
JQ实现新浪游戏首页幻灯片
2015/07/29 Javascript
JS实现简单的二维矩阵乘积运算
2016/01/26 Javascript
完美解决jQuery符号$与其他javascript 库、框架冲突的问题
2016/08/09 Javascript
Vue.js实现拖放效果的实例
2016/09/30 Javascript
JavaScript中全选、全不选、反选、无刷新删除、批量删除、即点即改入库(在yii框架中操作)的代码分享
2016/11/01 Javascript
JavaScript中的子窗口与父窗口的互相调用问题
2017/02/08 Javascript
深入理解Javascript中的观察者模式
2017/02/20 Javascript
js实现城市级联菜单的2种方法
2017/06/23 Javascript
浅谈vue引入css,less遇到的坑和解决方法
2018/01/20 Javascript
使用js实现单链解决前端队列问题的方法
2020/02/03 Javascript
vue 获取元素额外生成的data-v-xxx操作
2020/09/09 Javascript
jQuery实现动态操作table行
2020/11/23 jQuery
[03:17]DOTA2英雄基础教程 剧毒术士
2013/12/12 DOTA
[01:04:01]2014 DOTA2华西杯精英邀请赛5 24 DK VS VG
2014/05/25 DOTA
Python实现把数字转换成中文
2015/06/29 Python
python实现二维码扫码自动登录淘宝
2016/12/27 Python
python面向对象_详谈类的继承与方法的重载
2017/06/07 Python
Python基于pygame模块播放MP3的方法示例
2017/09/30 Python
Python简易版图书管理系统
2019/08/12 Python
Python 私有化操作实例分析
2019/11/21 Python
Python %r和%s区别代码实例解析
2020/04/03 Python
python获取整个网页源码的方法
2020/08/03 Python
西班牙品牌鞋子、服装和配饰在线商店:Esdemarca
2021/02/17 全球购物
银行工作检查书范文
2014/01/31 职场文书
招股说明书范本
2014/05/06 职场文书
三好生演讲稿
2014/09/12 职场文书
劳动争议和解协议书范本
2014/11/20 职场文书
结婚幸福感言
2015/08/01 职场文书
高端收音机+蓝牙音箱,JBL TUNER FM带收音蓝牙音箱评测
2021/04/24 无线电
如何用JavaScript实现一个数组惰性求值库
2021/05/05 Javascript
pytorch中的torch.nn.Conv2d()函数图文详解
2022/02/28 Python