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前后端同域名配置的方法实现
Mar 31 Servers
解决Nginx 配置 proxy_pass 后 返回404问题
Mar 31 Servers
浅谈Nginx 中的两种限流方式
Mar 31 Servers
Windows下使用Nginx+Tomcat做负载均衡的完整步骤
Mar 31 Servers
nginx限制并发连接请求数的方法
Apr 01 Servers
详解Apache SkyWalking 告警配置指南
Apr 22 Servers
教你快速构建一个基于nginx的web集群项目
Nov 27 Servers
Nginx+Windows搭建域名访问环境的操作方法
Mar 17 Servers
教你使用Jenkins集成Harbor自动发布镜像
Apr 03 Servers
Window server 2012 R2 AD域的组策略相关设置
Apr 28 Servers
Nginx文件已经存在全局反向代理问题排查记录
Jul 15 Servers
CentOS7 minimal 最小化安装网络设置过程
Dec 24 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
JavaScript创建命名空间的5种写法
2014/06/24 PHP
php+javascript实现的动态显示服务器运行程序进度条功能示例
2017/08/07 PHP
Laravel-admin之修改操作日志的方法
2019/09/30 PHP
php post换行的方法
2020/02/03 PHP
javascript cookies 设置、读取、删除实例代码
2010/04/12 Javascript
Firefox中autocomplete=&quot;off&quot; 设置不起作用Bug的解决方法
2011/03/25 Javascript
JS上传前预览图片实例
2013/03/25 Javascript
bootstrap改变按钮加载状态
2014/12/01 Javascript
JQuery右键菜单插件ContextMenu使用指南
2014/12/19 Javascript
分享10个优化代码的CSS和JavaScript工具
2016/05/11 Javascript
jquery实现图片列表鼠标移入微动
2016/12/01 Javascript
jquery+ajax实现省市区三级联动效果简单示例
2017/01/04 Javascript
在angular 6中使用 less 的实例代码
2018/05/13 Javascript
完美解决linux下node.js全局模块找不到的情况
2018/05/16 Javascript
详解Angular6学习笔记之主从组件
2018/09/05 Javascript
Vue中UI组件库之Vuex与虚拟服务器初识
2019/05/07 Javascript
Vue 页面权限控制和登陆验证功能的实例代码
2019/06/20 Javascript
Vue切换组件实现返回后不重置数据,保留历史设置操作
2020/07/21 Javascript
在Vue中使用Select选择器拼接label的操作
2020/10/22 Javascript
pandas 取出表中一列数据所有的值并转换为array类型的方法
2018/04/11 Python
django 使用 request 获取浏览器发送的参数示例代码
2018/06/11 Python
使用Pandas对数据进行筛选和排序的实现
2019/07/29 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
2019/12/04 Python
python 实现dict转json并保存文件
2019/12/05 Python
Django实现任意文件上传(最简单的方法)
2020/06/03 Python
如何用python写个模板引擎
2021/01/14 Python
html5-Canvas可以在web中绘制各种图形
2012/12/26 HTML / CSS
法国隐形眼镜网站:VisionDirect.fr
2020/03/03 全球购物
FragranceNet中文网:北美健康美容线上零售商
2020/08/26 全球购物
法定代表人身份证明书
2014/09/10 职场文书
普通党员整改措施
2014/10/24 职场文书
2014年幼儿园学期工作总结
2014/12/05 职场文书
考博导师推荐信范文
2015/03/27 职场文书
2016年大学校运会广播稿件
2015/12/21 职场文书
浅谈mysql执行过程以及顺序
2021/05/12 MySQL
mysql5.7使用binlog 恢复数据的方法
2021/06/03 MySQL