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 tp3.2.3 404问题解决方案
Mar 31 Servers
nginx配置proxy_pass中url末尾带/与不带/的区别详解
Mar 31 Servers
nginx反向代理配置去除前缀案例教程
Jul 26 Servers
nginx中封禁ip和允许内网ip访问的实现示例
Mar 17 Servers
阿里云 Windows server 2019 配置FTP
Apr 28 Servers
使用 Docker Compose 构建复杂的多容器App
Apr 30 Servers
阿里云服务器Ubuntu 20.04上安装Odoo 15
May 20 Servers
ubuntu下常用apt命令介绍
Jun 05 Servers
windows server 2016 域环境搭建的方法步骤(图文)
Jun 25 Servers
Windows Server 2012 R2服务器安装与配置的完整步骤
Jul 15 Servers
centos环境下nginx高可用集群的搭建指南
Jul 23 Servers
ubuntu20.04虚拟机无法上网的问题及解决
Dec 24 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
关于URL最大长度限制的相关资料查证
2014/12/23 PHP
tp框架(thinkPHP)实现三次登陆密码错误之后锁定账号功能示例
2018/05/24 PHP
phpwind放自动注册方法
2006/12/02 Javascript
$.ajax json数据传递方法
2008/11/19 Javascript
IE iframe的onload方法分析小结
2010/01/07 Javascript
在ASP.NET中使用JavaScript脚本的方法
2013/11/12 Javascript
JavaScript实现两个Table固定表头根据页面大小自行调整
2014/01/03 Javascript
jQuery页面加载初始化常用的三种方法
2014/06/04 Javascript
javascript自定义函数参数传递为字符串格式
2014/07/29 Javascript
jQuery中:last选择器用法实例
2014/12/30 Javascript
jquery.gridrotator实现响应式图片展示画廊效果
2015/06/23 Javascript
jQuery获取与设置iframe高度的方法
2016/08/01 Javascript
BootStrap中的表单大全
2016/09/07 Javascript
利用BootStrap的Carousel.js实现轮播图动画效果
2016/12/21 Javascript
node.js调用Chrome浏览器打开链接地址的方法
2017/05/17 Javascript
javascript实现文字无缝滚动效果
2017/08/26 Javascript
vue.js的手脚架vue-cli项目搭建的步骤
2017/08/30 Javascript
微信小程序动画(Animation)的实现及执行步骤
2018/10/28 Javascript
微信小程序 高德地图路线规划实现过程详解
2019/08/05 Javascript
基于layui的下拉列表的数据回显方法
2019/09/24 Javascript
[01:56]2014DOTA2西雅图邀请赛 MVP外卡赛老队长精辟点评
2014/07/09 DOTA
分析Python编程时利用wxPython来支持多线程的方法
2015/04/07 Python
Python实现将HTML转换成doc格式文件的方法示例
2017/11/20 Python
python paramiko利用sftp上传目录到远程的实例
2019/01/03 Python
django迁移数据库错误问题解决
2019/07/29 Python
python+rsync精确同步指定格式文件
2019/08/29 Python
python中栈的原理及实现方法示例
2019/11/27 Python
jupyter note 实现将数据保存为word
2020/04/14 Python
Python基于DB-API操作MySQL数据库过程解析
2020/04/23 Python
super()与this()的区别
2016/01/17 面试题
毕业生就业自荐书
2013/12/15 职场文书
小学生优秀评语大全
2014/04/22 职场文书
供电工程专业求职信
2014/08/09 职场文书
市场营销计划书
2015/01/17 职场文书
师范生教育见习总结
2015/06/23 职场文书
Windows 64位 安装 mysql 8.0.28 图文教程
2022/04/19 MySQL