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的rewrite模块详解
Mar 31 Servers
nginx处理http请求实现过程解析
Mar 31 Servers
Nginx 502 Bad Gateway错误原因及解决方案
Mar 31 Servers
Nginx代理同域名前后端分离项目的完整步骤
Mar 31 Servers
Kubernetes部署实例并配置Deployment、网络映射、副本集
Apr 01 Servers
在Docker容器中部署SQL Server
Apr 11 Servers
阿里云 Windows server 2019 配置FTP
Apr 28 Servers
使用Nginx的访问日志统计PV与UV
May 06 Servers
Nginx的gzip相关介绍
May 11 Servers
利用nginx搭建RTMP视频点播、直播、HLS服务器
May 25 Servers
nginx rewrite功能使用场景分析
May 30 Servers
Nginx跨域问题解析与解决
Aug 05 Servers
nginx之内存池的实现
vscode远程免密登入Linux服务器的配置方法
vscode内网访问服务器的方法
云服务器部署 Web 项目的实现步骤
在虚拟机中安装windows server 2008的图文教程
腾讯云服务器部署前后分离项目之前端部署
Jun 28 #Servers
windows系统安装配置nginx环境
Jun 28 #Servers
You might like
PHP判断远程图片或文件是否存在的实现代码
2014/02/20 PHP
ExtJS 入门
2010/10/29 Javascript
20个最新的jQuery插件
2012/01/13 Javascript
在Javascript中处理数组之toSource()方法的使用
2015/06/09 Javascript
基于bootstrap3和jquery的分页插件
2015/07/31 Javascript
jQuery实现验证码功能
2017/03/17 Javascript
Bootstrap标签页(Tab)插件使用方法
2017/03/21 Javascript
前端把html表格生成为excel表格的实例
2017/09/19 Javascript
搭建element-ui的Vue前端工程操作实例
2018/02/23 Javascript
JavaScript new对象的四个过程实例浅析
2018/07/31 Javascript
vue基于element-ui的三级CheckBox复选框功能的实现代码
2018/10/15 Javascript
如何解决webpack-dev-server代理常切换问题
2019/01/09 Javascript
vue+element加入签名效果(移动端可用)
2019/06/17 Javascript
微信小程序顶部导航栏可滑动并选中放大
2019/12/05 Javascript
node.js使用net模块创建服务器和客户端示例【基于TCP协议】
2020/02/14 Javascript
[01:01:04]2018DOTA2亚洲邀请赛 4.5 淘汰赛 OpTic vs TNC 第一场
2018/04/06 DOTA
Python 提取dict转换为xml/json/table并输出的实现代码
2016/08/28 Python
python正则表达式re之compile函数解析
2017/10/25 Python
Python实现的简单计算器功能详解
2018/08/25 Python
在Python中如何传递任意数量的实参的示例代码
2019/03/21 Python
HTML5 Notification(桌面提醒)功能使用实例
2014/03/17 HTML / CSS
美国男装连锁零售商:Men’s Wearhouse
2016/10/14 全球购物
英国美发和美容产品商城:HQhair
2019/02/08 全球购物
Noon埃及:埃及在线购物
2019/11/26 全球购物
POS解决方案:MUNBYN(热敏打印机、条形码扫描仪)
2020/06/09 全球购物
.NET程序员的数据库面试题
2012/10/10 面试题
How to spawning asynchronous work in J2EE
2016/08/29 面试题
毕业生找工作的自我评价
2013/10/18 职场文书
民主生活会发言材料
2014/10/20 职场文书
2014年乡镇安全生产工作总结
2014/12/02 职场文书
放射科岗位职责
2015/02/14 职场文书
刑事上诉状(无罪)
2015/05/23 职场文书
2016教师国培研修感言
2015/12/08 职场文书
心理学培训心得体会
2016/01/22 职场文书
MySQL 视图(View)原理解析
2021/05/19 MySQL
分享几个实用的CSS代码块
2022/06/10 HTML / CSS