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 相关文章推荐
Centos7.7 64位利用本地完整安装包安装lnmp/lamp套件教程
Mar 09 Servers
基于Nginx实现限制某IP短时间访问次数
Mar 31 Servers
nginx里的rewrite跳转的实现
Mar 31 Servers
Nginx下配置Https证书详细过程
Apr 01 Servers
配置nginx 重定向到系统维护页面
Jun 08 Servers
Nginx设置HTTPS的方法步骤 443证书配置方法
Mar 21 Servers
使用Docker容器部署rocketmq单机的全过程
Apr 03 Servers
Nginx隐藏式跳转(浏览器URL跳转后保持不变)
Apr 07 Servers
在Docker容器中部署SQL Server
Apr 11 Servers
微信告警的zabbix监控系统 监控整个NGINX集群
Apr 18 Servers
ubuntu下常用apt命令介绍
Jun 05 Servers
Nginx开源可视化配置工具NginxConfig使用教程
Jun 21 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
通过JavaScript或PHP检测Android设备的代码
2011/03/09 PHP
php 缩略图实现函数代码
2011/06/23 PHP
PHP使用CURL实现下载文件功能示例
2019/06/03 PHP
PHP实现单例模式建立数据库连接的方法分析
2020/02/11 PHP
javascript操作cookie_获取与修改代码
2009/05/21 Javascript
jQuery实现等比例缩放大图片让大图片自适应页面布局
2013/10/16 Javascript
JavaScript实现的链表数据结构实例
2015/04/02 Javascript
jquery序列化方法实例分析
2015/06/10 Javascript
JS实现消息来时让网页标题闪动效果的方法
2016/04/20 Javascript
JS实现漂亮的时间选择框效果
2016/08/20 Javascript
js窗口震动小程序分享
2016/11/28 Javascript
详解百度百科目录导航树小插件
2017/01/08 Javascript
vue v-on监听事件详解
2017/05/17 Javascript
nodeJS实现路由功能实例代码
2017/06/08 NodeJs
jQuery动态添加.active 实现导航效果代码思路详解
2017/08/29 jQuery
vue实现防抖的实例代码
2021/01/11 Vue.js
js实现电灯开关效果
2021/01/19 Javascript
[01:11]辉夜杯战队访谈宣传片—CDEC.Y
2015/12/26 DOTA
python求解水仙花数的方法
2015/05/11 Python
在Python中操作列表之List.append()方法的使用
2015/05/20 Python
浅析使用Python操作文件
2017/07/31 Python
Python实现时钟显示效果思路详解
2018/04/11 Python
Numpy 改变数组维度的几种方法小结
2018/08/02 Python
python实现播放音频和录音功能示例代码
2018/12/30 Python
python实现H2O中的随机森林算法介绍及其项目实战
2019/08/29 Python
Python使用psutil获取进程信息的例子
2019/12/17 Python
python连接打印机实现打印文档、图片、pdf文件等功能
2020/02/07 Python
python实现无边框进度条的实例代码
2020/12/30 Python
资源工程专业毕业生求职信
2014/02/27 职场文书
综治宣传月活动总结
2014/04/28 职场文书
基层党员四风问题自我剖析材料
2014/09/29 职场文书
房屋出售授权委托书
2014/10/12 职场文书
2014年食品安全工作总结
2014/12/04 职场文书
2015年全民国防教育日活动总结
2015/03/23 职场文书
正能量励志演讲稿三分钟(范文)
2019/07/11 职场文书
Python IO文件管理的具体使用
2022/03/20 Python