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配置80端口访问8080及项目名地址方法解析
Mar 31 Servers
nginx常用配置conf的示例代码详解
Mar 21 Servers
为Centos安装指定版本的Docker
Apr 01 Servers
Nginx隐藏式跳转(浏览器URL跳转后保持不变)
Apr 07 Servers
Consul在linux环境的集群部署
Apr 08 Servers
阿里云日志过滤器配置日志服务
Apr 09 Servers
Windows Server 2008 修改远程登录端口以及配置防火墙
Apr 28 Servers
解决IIS7下无法绑定https主机的问题
Apr 29 Servers
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
May 11 Servers
Linux磁盘管理方法介绍
Jun 01 Servers
vscode内网访问服务器的方法
Jun 28 Servers
服务器nginx权限被拒绝解决案例
Sep 23 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
解决file_get_contents无法请求https连接的方法
2013/12/17 PHP
php使用百度翻译api示例分享
2014/01/31 PHP
新浪微博OAuth认证和储存的主要过程详解
2015/03/27 PHP
Yii扩展组件编写方法实例分析
2015/06/29 PHP
PHP双向链表定义与用法示例
2018/01/31 PHP
基于jquery实现一张图片点击鼠标放大再点缩小
2013/09/29 Javascript
JS:window.onload的使用介绍
2013/11/13 Javascript
关于Javascript加载执行优化的研究报告
2014/12/16 Javascript
JavaScript获取DOM元素的11种方法总结
2015/04/25 Javascript
js时钟翻牌效果实现代码分享
2020/07/31 Javascript
微信小程序 scroll-view隐藏滚动条详解
2017/01/16 Javascript
nodejs npm错误Error:UNKNOWN:unknown error,mkdir 'D:\Develop\nodejs\node_global'at Error
2019/03/02 NodeJs
对Layer UI 模块化的用法详解
2019/09/26 Javascript
微信小程序拖拽排序列表的示例代码
2020/07/08 Javascript
python实现通过代理服务器访问远程url的方法
2015/04/29 Python
在Python的Django框架中simple-todo工具的简单使用
2015/05/30 Python
浅谈Python基础之I/O模型
2017/05/11 Python
python3+mysql查询数据并通过邮件群发excel附件
2018/02/24 Python
python opencv 图像尺寸变换方法
2018/04/02 Python
使用python代码进行身份证号校验的实现示例
2019/11/21 Python
用python给csv里的数据排序的具体代码
2020/07/17 Python
python em算法的实现
2020/10/03 Python
英国川宁茶官方网站:Twinings茶
2019/05/21 全球购物
毕业实习个人鉴定范文
2013/12/10 职场文书
运动会广播稿500字
2014/01/28 职场文书
党支部书记岗位责任制
2014/02/11 职场文书
毕业生就业意向书
2014/04/01 职场文书
优秀毕业生自荐信
2014/06/10 职场文书
学生违纪检讨书200字
2014/10/21 职场文书
故宫英文导游词
2015/01/31 职场文书
工程部主管岗位职责
2015/02/12 职场文书
水电施工员岗位职责
2015/04/11 职场文书
2019年描写人生经典诗句大全
2019/07/08 职场文书
总结Python连接CS2000的详细步骤
2021/06/23 Python
Javascript 解构赋值详情
2021/11/17 Javascript
Golang Web 框架Iris安装部署
2022/08/14 Python