Nginx源码分析 - 基础数据结构篇 - 双向链表结构 ngx_queue.c(05)

别再吐槽 C++ 标准库了!Nginx这两套数据结构,告诉你高性能的精髓 让我们首先看看void *elts;// 指向数组元素的指针// 当前数组中元素的数量// 单个元素的大小// 数组的容量(已分配的元素数量)// 关联的内存池elts:通用指针,指向实际的数组存储区域nelts:当前有效元素数量,相当于std::vector的size()size:单个元素的字节大小,支持任意类型的元素nalloc:已分配的总容量,相当于std::vector的capacity()pool:关联的内存池,这是与标准库最大的区别。 阅读详情

目录

一、数据结构定义

二、数据结构图

三、具体函数实现

1. 链表常用操作方法

2. 获取链表的主体结构 ngx_queue_data


Nginx的链表结构非常小巧和简单。设计的非常精巧。

通过链表的简单和精巧的设计,让Nginx的链表的数据结构和具体业务依赖进行了解耦。一般我们在设计c语言程序的时候,完全可以学习Nginx的这种数据结构的设计方式。

一、数据结构定义


链表数据结构 ngx_queue_t

typedef struct ngx_queue_s ngx_queue_t;

/**
 * 链表的数据结构非常简单,ngx_queue_s会挂载到实体
 * 结构上。然后通过ngx_queue_s来做成链表
 */
struct ngx_queue_s {
	ngx_queue_t *prev;
	ngx_queue_t *next;
};
  • prev:前一个元素。
  • next:后一个元素。

大家都看到这个链表的数据结构非常简单,甚至没有和任何的业务数据结构关联起来。但是如何用的呢?

一般情况下,会在业务的数据结构中,放置一个ngx_queue_t的数据结构。通过这个数据结构进行双向链表的连接。

例如下面的数据结构:

/**
 * 该结构体用于描述一个网络连接
 */
struct ngx_connection_s {
	void *data; //连接未使用时,data用于充当连接池中空闲链表中的next指针。连接使用时由模块而定,HTTP中,data指向ngx_http_request_t
	ngx_event_t *read; //连接对应的读事件
	ngx_event_t *write; //连接对应的写事件

	ngx_socket_t fd; //套接字句柄

	ngx_recv_pt recv; //直接接受网络字节流
	ngx_send_pt send; //直接发送网络字节流
	ngx_recv_chain_pt recv_chain; //网络字节流接收链表
	ngx_send_chain_pt send_chain; //网络字节流发送链表

	/*用来将当前连接以双向链表元素的形式添加到ngx_cycle_t核心结构体
	 * 的reuseable_connection_queue双向链表中,表示可以重用的连接*/
	ngx_queue_t queue;

	/* 省去部分 */
};

二、数据结构图


 

  • 整个链表实现的是双向链表。
  • 遍历链表后,获取链表的主体业务数据结构(上图为ngx_connection_s)使用ngx_queue_data方法
  • 链表和业务数据结构之间进行了解耦,使用更加灵活和方便。

三、具体函数实现


1. 链表常用操作方法


Nginx的链表用宏定义的方式定义了很多常用的双向链表操作方法。

/**
 * 初始化一个Q
 */
#define ngx_queue_init(q)                                                     \
    (q)->prev = q;                                                            \
    (q)->next = q

/**
 * 判断是否是空Q
 */
#define ngx_queue_empty(h)                                                    \
    (h == (h)->prev)

/**
 * 向链表H后面插入一个x的Q,支持中间插入
 */
#define ngx_queue_insert_head(h, x)                                           \
    (x)->next = (h)->next;                                                    \
    (x)->next->prev = x;                                                      \
    (x)->prev = h;                                                            \
    (h)->next = x

#define ngx_queue_insert_after   ngx_queue_insert_head

/**
 * 向链表H前面插入一个x的Q,支持中间插入
 */
#define ngx_queue_insert_tail(h, x)                                           \
    (x)->prev = (h)->prev;                                                    \
    (x)->prev->next = x;                                                      \
    (x)->next = h;                                                            \
    (h)->prev = x

/**
 * h是尾部,链表的第一个元素
 */
#define ngx_queue_head(h)                                                     \
    (h)->next

// h 是头,h 的上一个就是尾
#define ngx_queue_last(h)                                                     \
    (h)->prev

#define ngx_queue_sentinel(h)                                                 \
    (h)

/**
 * 返回节点Q的下一个元素
 */
#define ngx_queue_next(q)                                                     \
    (q)->next

/**
 * 返回节点Q的上一个元素
 */
#define ngx_queue_prev(q)                                                     \
    (q)->prev

#if (NGX_DEBUG)

/**
 * 移除某一个节点
 */
#define ngx_queue_remove(x)                                                   \
    (x)->next->prev = (x)->prev;                                              \
    (x)->prev->next = (x)->next;                                              \
    (x)->prev = NULL;                                                         \
    (x)->next = NULL

#else

#define ngx_queue_remove(x)                                                   \
    (x)->next->prev = (x)->prev;                                              \
    (x)->prev->next = (x)->next

#endif

//分割一个链表
#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;


#define ngx_queue_add(h, n)                                                   \
    (h)->prev->next = (n)->next;                                              \
    (n)->next->prev = (h)->prev;                                              \
    (h)->prev = (n)->prev;                                                    \
    (h)->prev->next = h;

2. 获取链表的主体结构 ngx_queue_data


前面我们已经看到,Nginx的ngx_queue_t数据结构是挂载在具体的业务数据结构上面的。通过ngx_queue_data,我们可以通过业务结构体中ngx_queue_t数据结构的偏移量来得到业务主体的数据结构的指针地址。

此函数,是Nginx 链表设计的关键点。

/**
 * 通过链表可以找到结构体所在的指针
 * typedef struct {
 * 		ngx_queue_s queue;
 * 		char * x;
 * 		....
 * } TYPE
 * 例如:ngx_queue_data(&type->queue, TYPE, queue)
 */
#define ngx_queue_data(q, type, link)                                         \
    (type *) ((u_char *) q - offsetof(type, link))

 

 

Nginx源码学习:我学到的4个反直觉设计:为什么C语言老手不用你以为的“标准做法“ void *data;// 指向实际数据每个节点包含一个data指针指向实际数据。这叫"非侵入式"设计——链表实现和数据结构完全解耦。Nginx的两个指针,16字节,没有任何数据字段。它要求使用者把节点嵌入到自己的结构体内部,然后通过offsetofoffsetofint value;// 嵌入的链表节点// 从链表节点反向获取宿主结构体这个技巧在Linux内核中无处不在——宏做的就是同样的事情。已知成员地址和成员在结构体中的偏移量,减一下就得到了结构体首地址。 阅读详情

相关推荐

【信息科学与工程学】计算机科学与自动化——第一百九十八篇 高并发高可用的知识点01

以上补充约 110 行,涵盖分布式协调、服务网格细节、数据库高级特性、性能分析工具、混沌工程、安全渗透、合规审计、研发效能、新兴技术、架构模式、实用工具及经典论文。涵盖数据库索引与锁、NoSQL、前端性能、安全攻防、压测工具深入、监控深入、云原生存储、服务治理扩展、代码质量、DevOps 文化、行业标准、软技能及未来趋势。好的,继续补充更多高并发、高可用、高可靠的知识与技术,涵盖更深层的数据库内部机制、分布式事务、服务治理、运维自动化、安全与前沿技术等领域。

weixin_49199313的博客 731

nginx 源码学习(四) 基本数据结构 ngx_queue_t

nginx 队列结构 ngx_queue_t  介绍 由于nginx 具有跨平台及C语言实现的特点,使nginx不宜使用一些第三方中间件提供的容器和算法,跨平台(linux,windows等)的特点, 因此nginx的代码必须可以跨平台编译运行,nginx选择了完全从头实现一遍基础的数据结构和算法,比如双向链表、动态数组、红黑树、 哈希表等,理解这些基础的数据结构和算法对于我们好处不言而

Daniel 的技术笔记 不积跬步无以至千里,不积小流无以成江海。 5752

C#上位机通过TCP实现库卡机器人实时位置返回与运动控制

TCP通讯是工业自动化中实现设备间可靠数据交换的基础协议,其核心原理在于面向连接的字节流传输与自定义报文格式。在机器人集成场景中,通过TCP协议可高效获取库卡机器人实时位置数据并下发运动控制指令,技术价值在于低延迟、高可靠的数据交互。典型应用包括产线数据采集、上位机监控与远程控制。C#上位机利用TcpClient与BinaryReader/Writer构建客户端,与库卡控制器EKI服务端配合,实现实时位置返回及运动控制,需关注报文定长设计、线程模型与断线重连等工程实践。

weixin_33937778的博客 394

nginx并发数设置_Nginx架构与Handler模块最详分析(1)

阅读本文之前可以看看之前的文章详解Nginx系列,可以了解的更加全面。1.nginx 架构nginx 在启动后,在 unix 系统中会以 daemon 的方式在后台运行,后台进程包含一个master 进程和多个 worker 进程。也可以手动地关掉后台模式,让 nginx 在前台运行,并且通过配置让 nginx 取消 master 进程,从而可以使 nginx 以单进程方式运行。很显然,生产环境下...

weixin_39880666的博客 284

视觉SLAM十四讲--第13讲 实践:设计SLAM系统(最详细的代码调试运行步骤)

最详细的代码调试运行避坑说明,也包含了我自己对代码的理解,如有理解错误的地方,欢迎指正交流。

记录和分享 1万+

实战解析:如何用Python逆向破解FastMoss的TikTok数据加密签名(附完整代码)

本文详细解析了如何用Python逆向破解FastMoss平台的TikTok数据加密签名机制,包括MD5加密算法和JS逆向分析。通过完整的Python代码示例,帮助开发者理解签名生成原理并实现自动化请求,提升数据获取能力。

weixin_30955617的博客 557

nginx基本数据结构 - ngx_queue_t使用举例

为Nginx提供了简单而强大的双向链表操作功能。其接口简洁,使用方便,适用于各种需要快速插入和删除元素的场景。在高并发的Nginx模块和其他代码中,提供了一种高效组织和管理数据的方法。通过对队列的高效操作,开发者可以极大地提升应用程序性能和稳定性,更好地处理并发数据流。

xx155802862xx的博客 268

从原理到应用:深入解析双编码器在机器人关节力矩感知中的实现

本文深入解析了双编码器方案在机器人关节力矩感知中的实现原理与应用。该方案通过在电机侧和输出侧分别安装编码器,利用两者位置差异间接高精度计算外力,克服了传统电流环精度不足和扭矩传感器成本高昂的缺点。它为实现协作机器人的丝滑拖动示教、灵敏碰撞检测以及足式机器人的动态平衡与柔顺控制提供了关键技术支撑,是目前高性能机器人力控的主流选择。

t8u9v0w1x的博客 662

07Nginx源码分析之双向链表结构(ngx_queue.c)

一 双向链表结构 Nginx的链表结构非常小巧和简单。设计的非常精巧。通过链表的简单和精巧的设计,让Nginx的链表的数据结构和具体业务依赖进行了解耦。 1 双向链表的数据结构 非常简单,不存任何其它类型的内容,只包含了链表的前后节点,使用时通过作为其它数据结构的成员使用。 typedef struct ngx_queue_s ngx_queue_t; struct ngx_queue_s { ngx_queue_t *prev; ngx_queue_t *next; }; 例如双向链表在业务上被

weixin_44517656的博客 265

探索数据库领域 SQL 的 JSON 数据处理技巧

在当今数字化时代,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,被广泛应用于各种领域,如 Web 应用、移动应用、大数据处理等。数据库作为数据存储和管理的核心,需要具备处理 JSON 数据的能力。本文章的目的在于深入探索 SQL 语言在数据库中处理 JSON 数据的技巧,涵盖从基础的 JSON 数据查询到复杂的 JSON 数据操作,帮助读者全面了解和掌握 SQL 处理 JSON 数据的方法。

2502_91592937的博客 924

第11节:GPU 线程层级:线程、线程块、网格

层级标识变量功能线程threadIdx执行单元,处理数据线程块blockIdx管理多个线程,提供共享内存网格管理多个 blockGPU 编程中,合理安排线程层级,是提升性能的关键。

yumeiguo的博客 210

nginx源码分析01 ngx_queue_t

小白一枚,开始认真分析nginx源码,先挑个简单的软柿子捏。 ngx_queue_t是nginx中的双向队列,由具有头结点的双向链表实现,注意:具有头结点。 偷一个大佬的图片,这张图片直观的展示了queue的实现方式。 直接分析一下代码 ngx_queue.h /* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h&gt

FuckMyLife 267

【YOLO系列】YOLOv5超详细解读(源码详解+入门实践+改进)

一文带你详细了解YOLOv5(含YOLO系列论文讲解+源码详解+入门实践+算法改进)

路人贾的博客 25万+

nginx高级数据结构源码分析(一)-----双向链表

ng_queue_t是Nginx提供的一个顺序容器,它以双向链表的方式将数据组织在一起。 链表作为顺序容器的优势在于,它可以高效的执行插入、删除、合并等操作,在移动链表中的元素时只需要修改指针的指向,因此,它很适合频繁修改容器的场合。 相对于其他顺序容器,它的优势有以下三点:   (1)  实现了排序功能,采用额是插入排序,虽然不太适合超大规模数据的排序,但是简单实用。 (2)  它非常轻

linuxcprimerapue的博客 640

《UDS协议从入门到精通》系列——图解0x23:通过地址读取内存

如何读取ECU中指定内存地址的数据?图解UDS 0x23服务带你快速上手!!

车载系统攻城狮 2623

第3讲:单端传输线的时域TDR仿真(基于实战的第一次仿真视角切换)

本文为CST仿真系列教程的第3讲,主要介绍传输线阻抗(TDR)的两种仿真方法:基于S参数的频域计算和基于高斯脉冲的时域计算。文章详细演示了在CST PCB Studio中修改电容参数、设置TDR仿真参数(包括截止时间和采样点数)的操作步骤,并通过对比实验展示TVS寄生电容对阻抗曲线的影响。最后将两种TDR方法的结果进行对比,验证了两种方法的一致性。本教程适合硬件工程师通过时域波形直观分析传输线阻抗特性,是信号完整性分析的重要技能。

一只豌豆象的博客 227

数据结构---nginx-1.7.12源码分析 (双向链表)

//  完美分析 请见: http://blog.csdn.net/chen19870707/article/details/40371047 Ngx_queue.h /* * ngx-queue.h * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include #include #ifn

梦想专栏 889

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

ngx_queue_insert_tail

【代码】ngx_queue_insert_tail。

weixin_41812346的博客 37

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

[nginx源码分析]location划分

nginx

Ubuntu黑客 1795

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

ngxin之main函数的解读(二)

上次说到ngx_connecntion_t,   现在看看ngx_connection_t的定义 struct ngx_connection_s { void *data; ngx_event_t *read; ngx_event_t *write;

dasgk的专栏 1175

Nginx源码学习-双向链表(ngx_queue_t)实现及实例分析

Nginx双向链表ngx_queue_t是采用"寄宿"在元素中的包含prev和next的ngx_queue_s来实现的。Linux内核中的page管理同样也使用到了这样的链接结构。linux内核情景分析 这样描述道:linux内核作者将prev和next从具体的“宿主”数据结构中抽象成为一个结构体list_head,这样list_head就可以成为该“宿主”的“连接件”。用ngx_queue_t结构串接起来的链表可以是不同类型的数据类型(只要这个数据类型包含ngx_quque_t这个数据结构)。打个不恰当的

ordeder的专栏 4329

Nginx高效数据结构(3)——队列(ngx_queue_t)

Nginx是我们学习编程的一个非常有参考价值的开源项目。良好的编码风格,高效的数据结构、架构设计

JK-Cool的博客 1357

nginx源码分析—队列结构ngx_queue_t

本博客(http://blog.csdn.net/livelylittlefish )贴出作者(阿波)相关研究、学习内容所做的笔记,欢迎广大朋友指正! Content 0. 序 1. 队列结构 2. 队列操作 2.1 在头节点之后插入 2.2 在尾节点之后插入 2.3 删除节点 2.4 分割队列 2.5 链接队列 2.6 获取中间

学习,思考,记录,分享。 5万+

NGINX源码之:ngx_queue

ngx_queue的debug与应用

qq_22351805的博客 715

Nginx 源码分析:ngx_queue_t

源文件路径 版本:1.8.0 src\core\Ngx_queue.h src\core\Ngx_queue.c 主要作用分析 ngx_queue_t是Nginx提供的双向链表。 通常意义上的双向链表是长成这个样子的: struct double_link_s { int node; d...

weixin_33759269的博客 171
上一篇: Nginx源码分析 - 基础数据结构篇 - 缓冲区结构 ngx_buf.c(04)
下一篇: Nginx源码分析 - 基础数据结构篇 - 单向链表结构 ngx_list.c(06)
老码农zhuli
老码农zhuli 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄14年 2456粉丝 312原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值