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处理http请求实现过程解析
Mar 31 Servers
Nginx反向代理及负载均衡如何实现(基于linux)
Mar 31 Servers
Nginx反爬虫策略,防止UA抓取网站
Mar 31 Servers
Apache Linkis 中间件架构及快速安装步骤
Mar 16 Servers
配置Kubernetes外网访问集群
Mar 31 Servers
nginx日志格式分析和修改
Apr 28 Servers
Nginx限流和黑名单配置
May 20 Servers
聊聊配置 Nginx 访问与错误日志的问题
May 25 Servers
windows server2008 开启端口的实现方法
Jun 25 Servers
Nginx如何限制IP访问只允许特定域名访问
Jul 23 Servers
Zabbix6通过ODBC方式监控Oracle 19C的详细过程
Sep 23 Servers
Elasticsearch6.2服务器升配后的bug(避坑指南)
Sep 23 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
php数组函数序列之array_keys() - 获取数组键名
2011/10/30 PHP
说说PHP的autoLoad自动加载机制
2012/09/27 PHP
使用php从身份证号中获取一系列线索(星座、生肖、生日等)
2016/05/11 PHP
PHP判断访客是否手机端(移动端浏览器)访问的方法总结【4种方法】
2019/03/27 PHP
JavaScript中常用的运算符小结
2012/01/18 Javascript
淘宝网提供的国内NPM镜像简介和使用方法
2014/04/17 Javascript
JavaScript入门教程之引用类型
2016/05/04 Javascript
Angular页面间切换及传值的4种方法
2016/11/04 Javascript
nodejs接入阿里大鱼短信验证码的方法
2017/07/10 NodeJs
Vue-Router进阶之滚动行为详解
2017/09/13 Javascript
jquery之基本选择器practice(实例讲解)
2017/09/30 jQuery
JavaScript的数据类型转换原则(干货)
2018/03/15 Javascript
读懂CommonJS的模块加载
2019/04/19 Javascript
详解Vue+ElementUI从零开始搭建自己的网站(一、环境搭建)
2019/04/30 Javascript
JS工厂模式开发实践案例分析
2019/10/17 Javascript
阿望教你用vue写扫雷小游戏
2020/01/20 Javascript
js实现动态时钟
2020/03/12 Javascript
在Vuex中Mutations修改状态操作
2020/07/24 Javascript
Python httplib模块使用实例
2015/04/11 Python
Python调用C++程序的方法详解
2017/01/24 Python
对Python3.6 IDLE常用快捷键介绍
2018/07/16 Python
Docker部署Python爬虫项目的方法步骤
2020/01/19 Python
python爬虫要用到的库总结
2020/07/28 Python
Python自动登录QQ的实现示例
2020/08/28 Python
Python 操作SQLite数据库的示例
2020/10/16 Python
工程项目经理岗位职责
2013/12/15 职场文书
授权委托书(完整版)
2014/09/10 职场文书
运动会400米加油稿(8篇)
2014/09/22 职场文书
全国法院系统开展党的群众路线教育实践活动综述(全文)
2014/10/25 职场文书
导师对论文的学术评语
2015/01/04 职场文书
演讲开场白和结束语
2015/05/29 职场文书
中国汉字听写大会观后感
2015/06/02 职场文书
你离财务总监还有多远?速览CFO的岗位职责
2019/11/18 职场文书
虚拟机linux端mysql数据库无法远程访问的解决办法
2021/05/26 MySQL
java objectUtils 使用可能会出现的问题
2022/02/28 Java/Android
css3新特性的应用示例分析
2022/03/16 HTML / CSS