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 相关文章推荐
Apache压力测试工具的安装使用
Mar 31 Servers
Nginx下配置Https证书详细过程
Apr 01 Servers
Nginx配置https的实现
Nov 27 Servers
Z-Order加速Hudi大规模数据集方案分析
Mar 31 Servers
nginx 配置指令之location使用详解
May 25 Servers
Python安装及建立虚拟环境的完整步骤
Jun 25 Servers
Windows Server 2012 R2服务器安装与配置的完整步骤
Jul 15 Servers
Nginx报404错误的详细解决方法
Jul 23 Servers
centos环境下nginx高可用集群的搭建指南
Jul 23 Servers
码云(gitee)通过git自动同步到阿里云服务器
Dec 24 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
Zend Guard一些常见问题解答
2008/09/11 PHP
php 调试利器debug_print_backtrace()
2012/07/23 PHP
用PHP来计算某个目录大小的方法
2014/04/01 PHP
getimagesize获取图片尺寸实例
2014/11/15 PHP
php自动更新版权信息显示的方法
2015/06/19 PHP
ExtJS Store的数据访问与更新问题
2010/04/28 Javascript
页面回到顶部的三种实现(锚标记,js)
2012/10/01 Javascript
js树插件zTree获取所有选中节点数据的方法
2015/01/28 Javascript
使用Jquery实现每日签到功能
2015/04/03 Javascript
基于jQuery实现动态数字展示效果
2015/08/12 Javascript
详解js图片轮播效果实现原理
2015/12/17 Javascript
老司机带你解读jQuery插件开发流程
2016/05/16 Javascript
基于jQuery下拉选择框插件支持单选多选功能代码
2016/06/07 Javascript
jQuery对table表格进行增删改查
2020/12/22 Javascript
JavaScript调试的多个必备小Tips
2017/01/15 Javascript
微信小程序 实现点击添加移除class
2017/06/12 Javascript
详解vue前后台数据交互vue-resource文档
2017/07/19 Javascript
bootstrap table服务端实现分页效果
2017/08/10 Javascript
详解升级react-router 4 踩坑指南
2017/08/14 Javascript
JavaScript-定时器0~9抽奖系统详解(代码)
2017/08/16 Javascript
bootstrap table实现点击翻页功能 可记录上下页选中的行
2017/09/28 Javascript
js原生实现移动端手指滑动轮播图效果的示例
2018/01/02 Javascript
解决jquery有正确返回值但不执行success函数的问题
2018/08/20 jQuery
python修改注册表终止360进程实例
2014/10/13 Python
Python遍历文件夹和读写文件的实现代码
2016/08/28 Python
浅谈python中的数字类型与处理工具
2017/08/02 Python
PyQt5实现从主窗口打开子窗口的方法
2019/06/19 Python
Python pyautogui模块实现鼠标键盘自动化方法详解
2020/02/17 Python
jupyter notebook 恢复误删单元格或者历史代码的实现
2020/04/17 Python
Ever New美国:澳大利亚领先的女装时尚品牌
2019/11/28 全球购物
Deux par Deux官方网站:设计师童装
2020/01/03 全球购物
金讯Java笔试题目
2013/06/18 面试题
早餐连锁店计划书
2014/01/08 职场文书
2015年管理人员工作总结
2015/05/13 职场文书
Canvas跟随鼠标炫彩小球的实现
2021/04/11 Javascript
pytorch分类模型绘制混淆矩阵以及可视化详解
2022/04/07 Python