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配置SSL证书出错解决方案
Mar 31 Servers
查看nginx配置文件路径和资源文件路径的方法
Mar 31 Servers
Nginx配置https原理及实现过程详解
Mar 31 Servers
Nginx配置80端口访问8080及项目名地址方法解析
Mar 31 Servers
nginx的zabbix 5.0安装部署的方法步骤
Jul 16 Servers
图文详解Nginx版本平滑升级方案
Sep 15 Servers
Minikube搭建Kubernetes集群
Mar 31 Servers
安装Windows Server 2012 R2企业版操作系统并设置好相关参数
Apr 29 Servers
Apache POI操作批量导入MySQL数据库
Jun 21 Servers
彻底卸载VMware虚拟机的超详细步骤记录
Jul 15 Servers
在windows server 2012 r2中安装mysql的详细步骤
Jul 23 Servers
Nginx如何获取自定义请求header头和URL参数详解
Jul 23 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
pw的一个放后门的方法分析
2007/10/08 PHP
php a simple smtp class
2007/11/26 PHP
php处理json时中文问题的解决方法
2011/04/12 PHP
PHP动态创建Web站点的方法
2011/08/14 PHP
PHP生成随机数的方法实例分析
2015/01/22 PHP
typecho插件编写教程(一):Hello World
2015/05/28 PHP
php 生成签名及验证签名详解
2016/10/26 PHP
js 文件引入实现代码
2010/04/23 Javascript
Knockout text绑定DOM的使用方法
2013/11/15 Javascript
Dojo Javascript 编程规范 规范自己的JavaScript书写
2014/10/26 Javascript
JS的数组迭代方法
2015/02/05 Javascript
原生javascript 学习之js变量全面了解
2016/07/14 Javascript
Vue数据驱动模拟实现3
2017/01/11 Javascript
canvas绘制万花筒效果(代码分享)
2017/01/20 Javascript
浅谈React和Redux的连接react-redux
2017/12/04 Javascript
React中常见的动画实现的几种方式
2018/01/10 Javascript
javascript for循环性能测试示例
2019/08/07 Javascript
详解JS预解析原理
2020/06/16 Javascript
[41:05]Serenity vs Pain 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python爬虫框架scrapy实现downloader_middleware设置proxy代理功能示例
2018/08/04 Python
Python实现的对一个数进行因式分解操作示例
2019/06/27 Python
python如何将两个txt文件内容合并
2019/10/18 Python
通过python连接Linux命令行代码实例
2020/02/18 Python
详解Python模块化编程与装饰器
2021/01/16 Python
Blue Nile蓝色尼罗河香港官网:世界最大在线钻石珠宝销售商
2020/05/07 全球购物
Big Green Smile法国:领先的英国有机和天然产品在线商店
2021/01/02 全球购物
大四学生找工作的自荐信
2014/03/27 职场文书
《白鹅》教学反思
2014/04/13 职场文书
安全责任书模板
2014/07/22 职场文书
党政领导班子民主生活会整改措施
2014/09/18 职场文书
社保缴纳证明申请书
2014/11/03 职场文书
小学教师年度个人总结
2015/02/05 职场文书
2015公司年度工作总结
2015/05/14 职场文书
行政答辩状范文
2015/05/21 职场文书
《叶问2》观后感
2015/06/15 职场文书
Hive导入csv文件示例
2022/06/25 数据库