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 过滤静态资源文件的访问日志的实现
Mar 31 Servers
详解Apache SkyWalking 告警配置指南
Apr 22 Servers
uwsgi+nginx代理Django无法访问静态资源的解决
May 10 Servers
Shell脚本一键安装Nginx服务自定义Nginx版本
Mar 20 Servers
Vertica集成Apache Hudi重磅使用指南
Mar 31 Servers
Nginx反向代理、重定向
Apr 13 Servers
nginx容器方式反向代理实战
Apr 18 Servers
Window server 2012 R2 AD域的组策略相关设置
Apr 28 Servers
nginx配置限速限流基于内置模块
May 02 Servers
本地搭建minio文件服务器(使用bat脚本启动)的方法
Jul 15 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
新版mysql+apache+php Linux安装指南
2006/10/09 PHP
如何在PHP中使用正则表达式进行查找替换
2013/06/13 PHP
zf框架的db类select查询器join链表使用示例(zend框架)
2014/03/14 PHP
迪菲-赫尔曼密钥交换(Diffie?Hellman)算法原理和PHP实现版
2015/05/12 PHP
PHP中引用类型和值类型功能与用法示例
2019/02/26 PHP
js实现权限树的更新权限时的全选全消功能
2009/02/17 Javascript
使用JSLint提高JS代码质量方法分享
2013/12/16 Javascript
屏蔽相应键盘按钮操作
2014/03/10 Javascript
php析构函数的具体用法小结
2014/03/11 Javascript
使用原生js封装webapp滑动效果(惯性滑动、滑动回弹)
2014/05/06 Javascript
javascript实现浏览器窗口传递参数的方法
2014/09/03 Javascript
Javascript实现单张图片浏览
2014/12/18 Javascript
javascript实现鼠标放上后下边对应内容变换的效果
2015/08/06 Javascript
基于JavaScript实现移除(删除)数组中指定元素
2016/01/04 Javascript
实例详解jQuery表单验证插件validate
2016/01/18 Javascript
Javascript之Math对象详解
2016/06/07 Javascript
javaScript语法总结
2016/11/25 Javascript
bootstrap导航栏、下拉菜单、表单的简单应用实例解析
2017/01/06 Javascript
纯js仿淘宝京东商品放大镜功能
2017/03/02 Javascript
细说webpack源码之compile流程-rules参数处理技巧(2)
2017/12/26 Javascript
vue2.0 elementUI制作面包屑导航栏
2018/02/22 Javascript
Python实现列表删除重复元素的三种常用方法分析
2017/11/24 Python
Python 查看文件的读写权限方法
2018/01/23 Python
使用python对excle和json互相转换的示例
2018/10/23 Python
python中with用法讲解
2020/02/07 Python
python math模块的基本使用教程
2021/01/16 Python
简单掌握CSS3中resize属性的用法
2016/04/01 HTML / CSS
CSS 说明横向进度条最后显示文字的实现代码
2020/11/10 HTML / CSS
使用canvas实现黑客帝国数字雨效果
2020/01/02 HTML / CSS
Sony C++笔试题
2013/03/10 面试题
军训心得体会
2013/12/31 职场文书
特色蛋糕店创业计划书
2014/01/28 职场文书
工作所在部门证明
2014/09/21 职场文书
2014年营业员工作总结
2014/11/18 职场文书
老公婚前保证书
2015/02/28 职场文书
《怀念母亲》教学反思
2016/02/19 职场文书