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
Mac环境Nginx配置和访问本地静态资源的实现
Mar 31 Servers
使用Docker容器部署rocketmq单机的全过程
Apr 03 Servers
Nginx禁止ip访问或非法域名访问
Apr 07 Servers
Linux下使用C语言代码搭建一个简单的HTTP服务器
Apr 13 Servers
openstack云计算keystone组件工作介绍
Apr 20 Servers
Windows server 2012 配置Telnet以及用法详解
Apr 28 Servers
Nginx 常用配置
May 15 Servers
Tomcat 与 maven 的安装与使用教程
Jun 16 Servers
Apache自带的ab压力测试工具的实现
Jul 23 Servers
教你使用Ubuntu搭建DNS服务器
Sep 23 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
PHP实现微信退款的方法示例
2019/03/26 PHP
MSN消息提示类
2006/09/05 Javascript
IE和Firefox在JavaScript应用中的兼容性探讨
2008/04/01 Javascript
原生js实现shift/ctrl/alt按键的获取
2013/04/08 Javascript
js在输入框屏蔽按键,只能键入数字的示例代码
2014/01/03 Javascript
html dom节点操作(获取/修改/添加或删除)
2014/01/23 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
2014/09/04 Javascript
探讨js字符串数组拼接的性能问题
2014/10/11 Javascript
node.js中的emitter.on方法使用说明
2014/12/10 Javascript
浅谈jQuery中的事件
2015/03/23 Javascript
ionic在开发ios系统微信时键盘挡住输入框的解决方法(键盘弹出问题)
2016/09/06 Javascript
详解JavaScript时间处理之几个月前或几个月后的指定日期
2016/12/21 Javascript
AngularJS打开页面隐藏显示表达式用法示例
2016/12/25 Javascript
JavaScript和jQuery制作光棒效果
2017/02/24 Javascript
jQuery插件HighCharts绘制2D柱状图、折线图的组合双轴图效果示例【附demo源码下载】
2017/03/09 Javascript
angular.JS实现网页禁用调试、复制和剪切
2017/03/31 Javascript
webpack独立打包和缓存处理详解
2017/04/03 Javascript
浅谈angular.copy() 深拷贝
2017/09/14 Javascript
jQuery插件实现弹性运动完整示例
2018/07/07 jQuery
uniapp实现可滑动选项卡
2020/10/21 Javascript
JavaScript实现刮刮乐效果
2020/11/01 Javascript
[03:40]DOTA2抗疫特别篇《英雄年代》
2020/02/28 DOTA
scrapy spider的几种爬取方式实例代码
2018/01/25 Python
Python+selenium 获取一组元素属性值的实例
2018/06/22 Python
详解Django中间件的5种自定义方法
2018/07/26 Python
python使用Paramiko模块实现远程文件拷贝
2019/04/30 Python
Python将文字转成语音并读出来的实例详解
2019/07/15 Python
pytorch实现特殊的Module--Sqeuential三种写法
2020/01/15 Python
英国高街奥特莱斯:Highstreet Outlet
2019/11/21 全球购物
入股协议书范本
2014/04/14 职场文书
北京离婚协议书范文2014
2014/09/29 职场文书
党的群众路线教育实践活动个人对照检查材料(医生)
2014/11/05 职场文书
2014年检验科工作总结
2014/11/22 职场文书
综合测评个人总结
2015/03/03 职场文书
幼儿园教师节活动总结
2015/03/23 职场文书
Python基础之变量的相关知识总结
2021/06/23 Python