nginx 单向链表

news2025/1/16 16:42:04

ngx_list_t是Nginx封装的链表容器,它在Nginx中使用得很频繁,例如HTTP的头部就是用
ngx_list_t来存储的。当然,C语言封装的链表没有C++或Java等面向对象语言那么容易理解。
ngx_list_t单向链表与ngx_queue_t双向链表是完全不同的,它是负责容器内元素内存分配
的,因此,这两个容器在通用性的设计思路上是完全不同的。同时它与ngx_array_t也不一
样,它不是用完全连续的内存来存储元素,而是用单链表将多段内存块连接起来,每段内存块也存储了多个元素,有点像“数组+单链表”。先看一下ngx_list_t相关成员的定义:

typedef struct ngx_list_part_s  ngx_list_part_t;

struct ngx_list_part_s {
    void             *elts;
    ngx_uint_t        nelts;
    ngx_list_part_t  *next;
};


typedef struct {
    ngx_list_part_t  *last;
    ngx_list_part_t   part;
    size_t            size;
    ngx_uint_t        nalloc;
    ngx_pool_t       *pool;
} ngx_list_t;

ngx_list_t描述整个链表,而ngx_list_part_t只描述链表的一个元素。这里要注意的是,ngx_list_t不是一个单纯的链表,为了便于理解,我们姑且称它为存储数组的链表,什么意思呢?抽象地说,就是每个链表元素ngx_list_part_t又是一个数组,拥有连续的内存,它既依赖于ngx_list_t里的size和nalloc来表示数组的容量,同时又依靠每个ngx_list_part_t成员中的nelts来表示数组当前已使用了多少容量。因此,ngx_list_t是一个链表容器,而链表中的元素又是一个数组。事实上,ngx_list_part_t数组中的元素才是用户想要存储的东西,ngx_list_t链表能够容纳的元素数量由ngx_list_part_t数组元素的个数与每个数组所能容纳的元素相乘得到。
这样设计有什么好处呢?

  • 链表中存储的元素是灵活的,它可以是任何一种数据结构。
  • 链表元素需要占用的内存由ngx_list_t管理,它已经通过数组分配好了。
  • 小块的内存使用链表访问效率是低下的,使用数组通过偏移量来直接访问内存则要高效得多。

下面详述每个成员的意义

  • ngx_list_t
    • part:链表的首个数组元素。
    • last:指向链表的最后一个数组元素。
    • size:前面讲过,链表中的每个ngx_list_part_t元素都是一个数组。因为数组存储的是某种类型的数据结构,且ngx_list_t是非常灵活的数据结构,所以它不会限制存储什么样的数据,只是通过size限制每一个数组元素的占用的空间大小,也就是用户要存储的一个数据所占用的字节数必须小于或等于size。
    • nalloc:链表的数组元素一旦分配后是不可更改的。nalloc表示每个ngx_list_part_t数组的容量,即最多可存储多少个数据。
    • pool:链表中管理内存分配的内存池对象。用户要存放的数据占用的内存都是由pool分配的,下文中会详细介绍。

  • ngx_list_part_t
    • elts:指向数组的起始地址。
    • nelts:表示数组中已经使用了多少个元素。当然,nelts必须小于ngx_list_t结构体中的nalloc。
    • next:下一个链表元素ngx_list_part_t的地址。

事实上,ngx_list_t中的所有数据都是由ngx_pool_t类型的pool内存池分配的,它们通常都是连续的内存(在由一个pool内存池分配的情况下)。下图可以看一下ngx_list_t的内存分布情况。


ngx_list_t的内存分布

如上是由3个ngx_list_part_t数组元素组成的ngx_list_t链表可能拥有的一种内存分布结构,读者可以从这种较为常见的内存分布中看到ngx_list_t链表的用法。这里,pool内存池为其分配了连续的内存,最前端内存存储的是ngx_list_t结构中的成员,紧接着是第一个ngx_list_part_t结构占用的内存,然后是ngx_list_part_t结构指向的数组,它们一共占用size*nalloc字节,表示数组中拥有nalloc个大小为size的元素。其后面是第2个ngx_list_part_t结构以及它所指向的数组,依此类推。
对于链表,Nginx提供的接口包括:ngx_list_create接口用于创建新的链表,ngx_list_init接口用于初始化一个已有的链表,ngx_list_push接口用于添加新的元素,如下所示:

static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    list->part.elts = ngx_palloc(pool, n * size);
    if (list->part.elts == NULL) {
        return NGX_ERROR;
    }

    list->part.nelts = 0;
    list->part.next = NULL;
    list->last = &list->part;
    list->size = size;
    list->nalloc = n;
    list->pool = pool;

    return NGX_OK;
}

ngx_list_t *
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    ngx_list_t  *list;

    list = ngx_palloc(pool, sizeof(ngx_list_t));
    if (list == NULL) {
        return NULL;
    }

    list->part.elts = ngx_palloc(pool, n * size);
    if (list->part.elts == NULL) {
        return NULL;
    }

    list->part.nelts = 0;
    list->part.next = NULL;
    list->last = &list->part;
    list->size = size;
    list->nalloc = n;
    list->pool = pool;

    return list;
}


void *
ngx_list_push(ngx_list_t *l)
{
    void             *elt;
    ngx_list_part_t  *last;

    last = l->last;

    if (last->nelts == l->nalloc) {

        /* the last part is full, allocate a new list part */

        last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
        if (last == NULL) {
            return NULL;
        }

        last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
        if (last->elts == NULL) {
            return NULL;
        }

        last->nelts = 0;
        last->next = NULL;

        l->last->next = last;
        l->last = last;
    }

    elt = (char *) last->elts + l->size * last->nelts;
    last->nelts++;

    return elt;
}

调用ngx_list_create创建元素时,pool参数是内存池对象,size是每个元素的大小,n是每个链表数组可容纳元素的个数(相当于ngx_list_t结构中的nalloc成员)。
ngx_list_create返回新创建的链表地址,如果创建失败,则返回NULL空指针。ngx_list_create被调用后至少会创建一个数组(不会创建空链表),其中包含n个大小为size字节的连续内存块,也就是ngx_list_t结构中的part成员。
下面看一个简单的例子,我们首先建立一个链表,它存储的元素是ngx_str_t,其中每个链表数组中存储4个元素,代码如下所示:

ngx_list_t* testlist = ngx_list_create(r->pool, 4,sizeof(ngx_str_t));
    if (testlist == NULL) {
        return NGX_ERROR;
    }

ngx_list_init的使用方法与ngx_list_create非常类似,需要注意的是,这时链表数据结构已经创建好了,若ngx_list_init返回NGX_OK,则表示初始化成功,若返回NGX_ERROR,则表示失败。
调用ngx_list_push表示添加新的元素,传入的参数是ngx_list_t链表。正常情况下,返回的是新分配的元素首地址。如果返回NULL空指针,则表示添加失败。在使用它时通常先调用ngx_list_push得到返回的元素地址,再对返回的地址进行赋值。例如:

ngx_str_t* str = ngx_list_push(testlist);
    if (str == NULL) {
        return NGX_ERROR;
    }
    str->len= sizeof("Hello world");
    str->data = "Hello world";

遍历链表时Nginx没有提供相应的接口,实际上也不需要。我们可以用以下方法遍历链表中的元素:

/*
 *
 *  the iteration through the list:
 *
 *  part = &list.part;
 *  data = part->elts;
 *
 *  for (i = 0 ;; i++) {
 *
 *      if (i >= part->nelts) {
 *          if (part->next == NULL) {
 *              break;
 *          }
 *
 *          part = part->next;
 *          data = part->elts;
 *          i = 0;
 *      }
 *
 *      ...  data[i] ...
 *
 *  }
 */

原文链接;https://zhuanlan.zhihu.com/p/52221866 

(免费订阅,永久学习)学习地址:C/C++Linux服务器开发/后台架构师  

更多相关学习资料有需要的可以自行报名学习,免费订阅,永久学习,或点击这里加qun免费
领取,关注我持续更新哦! !  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/24016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序直播系统开发制作_分享视频直播系统开发对企业的好处

许多小伙伴可能会感到困惑,直播小程序怎么制作,有直播小程序制作教程吗?为什么选择直播小程序,它会给企业带来什么好处?下面小编给大家一一解答。 一、小程序直播系统开发制作教程 ① 进入开发工具选择所在行业的模板…

Multigrid reinforcement learning with reward shaping

摘要 基于势能的奖励塑形已被证明是提高强化学习agent收敛速度的有效方法。 这是一种以原则性方式将背景知识纳入时间差分学习的灵活技术。然而,问题仍然是如何计算用于塑形给予学习agent的奖励的势能。在本文中,我们提出了一种通过状态空间离散化来解决…

计算机毕业设计java+ssm的高校科研仪器共享平台-计算机毕业设计

项目介绍 高校科研仪器共享平台,是一个学校内部提供信息管理的平台,是完全的,高速的,开放的,其核心思想是提供一个以自然语言为主的用户界面,让用户能够更好的刚加方便快捷的管理科研仪器信息的一个渠道和…

解决雪花算法生成的ID传输前端后精度丢失

本章目录: 问题描述解决方案 修改数据库字段配置MVC全局消息转换器修改Result类一、问题描述 在用雪花算法生成的ID传输到前端时,会出现后三位精度丢失 可以看到,我们得到的response为1594605819398193154 而前端展示的为159460581939819…

3 Minute Thesis (3MT)

1 定义 资料来源:https://zhuanlan.zhihu.com/p/63325983?utm_id0 3MT原则:要把博士课题介绍给一个受过高等教育但没有专业背景的人并阐述它的重要性。 定义:三分钟论文(3MT)是一个学术比赛,帮助当前的研究生培养有效的演讲和沟…

[附源码]计算机毕业设计JAVA基于web的电子产品网络购物平台

[附源码]计算机毕业设计JAVA基于web的电子产品网络购物平台 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术:…

MyBatis搭建

目录 1.我的开发环境 2.创建maven工程 (1)打包方式 : jar (2)引入依赖 3.创建MyBatis的核心配置文件 4.创建mapper接口 5.创建MyBatis的映射文件 1.映射文件的命名规则: 2.MyBatis中可以面向接口操作数据 , 要保证两个一致 : 映射文件官方示例: 6.执行配置文件中的SQL…

HC-05蓝牙模块--------手机与STM32通信(代码编写)(上位机配置)保姆级教程

⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。 ⏩因为之前无论是电赛还是做项目,都用到了蓝牙模块,如:手机和stm32的通信,电赛中的双车通信,还是遥感小车的…

19 01-通过状态掩码读取DTC数目

诊断协议那些事儿 诊断协议那些事儿专栏系列文章,本文介绍存储数据传输服务下的19服务ReadDTClnformation的第一个子功能(01h),通过状态掩码读取DTC数目。 关联文章: 19服务List $19服务:DTCStatusMask和statusofDT…

肠道菌群化合物库——科研领域的研究靶点

近年来,肠道菌群已经成为科研领域的研究热点,涉及领域之广泛,最近几年的研究主要集中在肠道菌群与多种疾病发生和发展的联系。近年来,肠道菌群时常登上各大国际学术周刊,实火! “闻声而来”的肠道菌群肠道…

【异构知识蒸馏:IVIF】

Heterogeneous Knowledge Distillation for Simultaneous Infrared-Visible Image Fusion and Super-Resolution (同时进行红外-可见光图像融合和超分辨率的异构知识蒸馏) 近年来,红外-可见光图像融合引起了越来越多的关注,并且…

数据采集网关如何打破数据孤岛,实现工业物联网

企业数字化发展到一定水平,就可能出现不平衡,催生出“数据孤岛”的现象。 企业内部存在多个设备多个系统,都有各自的数据,分门别类进行存储,这些部分之间累又建立有效的数据交换渠道,协议标准业不一致&…

实战讲解网关接口统一认证SpringCloudGateway(图+文)

1 缘起 继gateway限流篇:https://blog.csdn.net/Xin_101/article/details/127890605 之后,继续补充网关统一鉴权的相关应用, 网关作为所有流量入口,承接所有请求,因此,可以在网关层统一做鉴权,…

MIT6.830-2022-lab1实验思路详细讲解

文章目录前言一、6.830/Lab1 Start二、Exercise2.1、Exercise1:Fields and Tuples2.2、Exercise2:Catalog2.3、Exercise3:BufferPool2.4、Exercise4:HeapFile access method2.5、Exercise5:HeapFile2.6、Exercise6&…

DJ12-2-2 算术运算指令

目录 1. 加法指令 (1)ADD 指令 (2)ADC 指令 (3)INC 指令 2. 减法指令 (1)SUB 指令 (2)SBB 指令 (3)DEC 指令 (4&…

Alluxio 2.9新版发布 | 重塑架构,支持大规模多租户环境

/ Alluxio宣布正式发布数据编排平台2.9版本 / Alluxio 2.9 版本的主要新增功能包括: 新增跨环境集群同步功能、增强Alluxio在Kubernetes上的可管理性、提高S3 API 安全性和用户体验 2022年11月17日,全球首创的开源数据编排软件开发商Alluxio宣布正式发…

1.2 分布

测度理论 (Durrett) 第五版 个人笔记 答案 Durrett高等概率论教材 (Probability) 攻读概率及统计/机器学习应用方向博士学位. Measure TheoryProbability SpacesDistributionsRandom VariablesIntegrationProperties of the IntegralExpected ValueProduct Measures, Fubini’…

[计算机毕业设计]机器视觉指纹识别图像识别

前言 📅大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科同学来说是充满挑战。为帮助大家顺利通过…

2022Q3运动户外行业数据分析(高增长概念解读)

本篇我们将继续来分析22年Q3季度中,运动户外行业的高增长概念。 在运动户外行业中,我们发现了3个高增长品类,分别是:泳镜、运动休闲鞋、运动包。 一、游泳用品高增长概念——泳镜 在功能上区分,泳镜可以分为竞速泳镜、…

十秒钟搞懂linux的软硬链接细节图解和目录结构文件的基本命令

秒懂linux链接图解一,软硬链接的分析1,软链接的图解:2,硬链接的图解3,软硬链接的区别4,目录创建软链接的语法格式二,linxu的根目录结构示意图和各部分的功能,可以根据单词部分记忆(部…