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实现反向代理
Sep 20 Servers
Nginx优化服务之网页压缩的实现方法
Mar 31 Servers
Nginx如何配置Http、Https、WS、WSS的方法步骤
May 11 Servers
学习nginx基础知识
Sep 04 Servers
nginx内存池源码解析
Nov 20 Servers
忘记Grafana不要紧2种Grafana重置admin密码方法详细步骤
Apr 07 Servers
Nginx 匹配方式
May 15 Servers
详解Nginx的超时keeplive_timeout配置步骤
May 25 Servers
Windows server 2012 NTP时间同步的实现
Jun 25 Servers
vscode远程免密登入Linux服务器的配置方法
Jun 28 Servers
如何让你的Nginx支持分布式追踪详解
Jul 07 Servers
Fluentd搭建日志收集服务
Sep 23 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
用Zend Encode编写开发PHP程序
2006/10/09 PHP
php记录代码执行时间(实现代码)
2013/07/05 PHP
php数组去除空值函数分享
2015/02/02 PHP
thinkPHP2.1自定义标签库的导入方法详解
2016/07/20 PHP
PHP实现中国公民身份证号码有效性验证示例代码
2017/05/03 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
2017/11/14 PHP
jQuery ajax BUG:object doesn't support this property or method
2010/07/06 Javascript
JQuery 选择器、过滤器介绍
2011/02/14 Javascript
jquery实现div阴影效果示例代码
2013/09/16 Javascript
jquery背景跟随鼠标滑动导航
2015/11/20 Javascript
JS组件Bootstrap Table使用方法详解
2016/02/02 Javascript
基于javascript html5实现3D翻书特效
2016/03/14 Javascript
利用jQuery的动画函数animate实现豌豆发射效果
2016/08/28 Javascript
JavaScript实现点击按钮复制指定区域文本(推荐)
2016/11/25 Javascript
JS中type=&quot;button&quot;和type=&quot;submit&quot;的区别
2017/07/04 Javascript
Vue匿名插槽与作用域插槽的合并和覆盖行为
2019/04/22 Javascript
Ant-design-vue Table组件customRow属性的使用说明
2020/10/28 Javascript
Python实现爬虫设置代理IP和伪装成浏览器的方法分享
2018/05/07 Python
对numpy中数组转置的求解以及向量内积计算方法
2018/10/31 Python
python3.4爬虫demo
2019/01/22 Python
对python中字典keys,values,items的使用详解
2019/02/03 Python
使用PyQt4 设置TextEdit背景的方法
2019/06/14 Python
python多继承(钻石继承)问题和解决方法简单示例
2019/10/21 Python
TensorFlow dataset.shuffle、batch、repeat的使用详解
2020/01/21 Python
乐天旅游香港网站:日本饭店预订
2017/11/29 全球购物
嘻哈珠宝品牌:KRKC&CO
2020/10/19 全球购物
加拿大拼图大师:Puzzle Master
2020/12/28 全球购物
学前教育毕业生自荐信
2013/10/29 职场文书
财务会计应届生求职信
2013/11/24 职场文书
清扬洗发水广告词
2014/03/14 职场文书
企业员工集体活动方案
2014/08/17 职场文书
个人批评与自我批评发言稿
2014/09/28 职场文书
事业单位年度考核个人总结
2015/02/12 职场文书
校本培训个人总结
2015/02/28 职场文书
教师工作能力自我评价
2015/03/04 职场文书
施工单位工程部经理岗位职责
2015/04/09 职场文书