nginx学习-链表结构ngx_list_t

Content

1.链表结构

1.2 ngx_list_t的逻辑结构

2.1创建链表

3.一个例子

3.2如何编译

4.小结


0. 序

 

本文继续介绍nginx的容器——链表。

链表实现文件:文件:./src/core/ngx_list.h/.c。.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4。

1. 链表结构

 

1.1 ngx_list_t结构

 

nginx的链表(头)结构为ngx_list_t,链表节点结构为ngx_list_part_t,定义如下。

[cpp]  view plain copy
  1. typedef struct ngx_list_part_s ngx_list_part_t;  
  2.    
  3. struct ngx_list_part_s {      //链表节点结构  
  4.     void             *elts;   //指向该节点实际的数据区(该数据区中可以存放nalloc个大小为size的元素)  
  5.     ngx_uint_t        nelts;  //实际存放的元素个数  
  6.     ngx_list_part_t  *next;   //指向下一个节点  
  7. };  
  8.    
  9. typedef struct{              //链表头结构  
  10.     ngx_list_part_t  *last;   //指向链表最后一个节点(part)  
  11.     ngx_list_part_t   part;   //链表头中包含的第一个节点(part)  
  12.     size_t            size;   //每个元素大小  
  13.     ngx_uint_t        nalloc; //链表所含空间个数,即实际分配的小空间的个数  
  14.     ngx_pool_t       *pool;   //该链表节点空间在此内存池中分配  
  15. }ngx_list_t;  


其中,sizeof(ngx_list_t)=28,sizeof(ngx_list_part_t)=12。

 

由此可见,nginx的链表也要从内存池中分配。对于每一个节点(list part)将分配nalloc个大小为size的小空间,实际分配的大小为(nalloc * size)。详见下文的分析。

 

1.2 ngx_list_t的逻辑结构

 

ngx_list_t结构引用了ngx_pool_t结构,因此本文参考nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理一文画出相关结构的逻辑图,如下。注:本文采用UML的方式画出该图。

 

2. 链表操作

 

链表操作共3个,如下。

[cpp]  view plain copy
  1. //创建链表  
  2. ngx_list_t*ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);  
  3.    
  4. //初始化链表  
  5. static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool,  
  6.     ngx_uint_tn, size_t size);  
  7.    
  8. //添加元素  
  9. void*ngx_list_push(ngx_list_t *l)  

他们的实现都很简单,本文只分析创建链表和添加元素操作。

 

2.1创建链表

 

创建链表的操作实现如下,首先分配链表头(28B),然后分配头节点(即链表头中包含的part)数据区,两次分配均在传入的内存池(pool指向的内存池)中进行。然后简单初始化链表头并返回链表头的起始位置。

[cpp]  view plain copy
  1. ngx_list_t *  
  2. ngx_list_create(ngx_pool_t*pool, ngx_uint_t n, size_t size)  
  3. {  
  4.     ngx_list_t *list;  
  5.    
  6.     list = ngx_palloc(pool,sizeof(ngx_list_t));  //从内存池中分配链表头  
  7.     if (list == NULL) {  
  8.         return NULL;  
  9.     }  
  10.    
  11.     list->part.elts =ngx_palloc(pool, n * size); //接着分配n*size大小的区域作为链表数据区  
  12.     if (list->part.elts == NULL) {  
  13.         return NULL;  
  14.     }  
  15.    
  16.     list->part.nelts = 0;     //初始化  
  17.     list->part.next = NULL;  
  18.     list->last = &list->part;  
  19.     list->size = size;  
  20.     list->nalloc = n;  
  21.     list->pool = pool;  
  22.    
  23.     return list;    //返回链表头的起始位置  
  24. }  
创建链表后内存池的物理结构图如下。


2.2添加元素

 

添加元素操作实现如下,同nginx数组实现类似,其实际的添加操作并不在该函数中完成。函数ngx_list_push返回可以在该链表数据区中放置元素(元素可以是1个或多个)的位置,而添加操作即在获得添加位置之后进行,如后文的例子。

[cpp]  view plain copy
  1. void *  
  2. ngx_list_push(ngx_list_t*l)  
  3. {  
  4.     void             *elt;  
  5.     ngx_list_part_t  *last;  
  6.    
  7.     last = l->last;  
  8.    
  9.     if (last->nelts ==l->nalloc) {  //链表数据区满  
  10.    
  11.         /* the last part is full, allocate anew list part */  
  12.    
  13.         last =ngx_palloc(l->pool, sizeof(ngx_list_part_t));  //分配节点(list part)  
  14.         if (last == NULL) {  
  15.             return NULL;  
  16.         }  
  17.    
  18.         last->elts =ngx_palloc(l->pool, l->nalloc * l->size);//分配该节点(part)的数据区  
  19.         if (last->elts == NULL) {  
  20.             return NULL;  
  21.         }  
  22.    
  23.         last->nelts = 0;  
  24.         last->next = NULL;  
  25.    
  26.         l->last->next =last;  //将分配的list part插入链表  
  27.         l->last = last;        //并修改list头的last指针  
  28.     }  
  29.    
  30.     elt = (char *)last->elts + l->size * last->nelts; //计算下一个数据在链表数据区中的位置  
  31.     last->nelts++;  //实际存放的数据个数加1  
  32.    
  33.     return elt;  //返回该位置  
  34. }  

由此可见,向链表中添加元素实际上就是从内存池中分配链表节点(part)及其该节点的实际数据区,并修改链表节点(part)信息。

 

注1:与数组的区别,数组数据区满时要扩充数据区空间;而链表每次要分配节点及其数据区。

注2:链表的每个节点(part)的数据区中可以放置1个或多个元素,这里的元素可以是一个整数,也可以是一个结构。

 

下图是一个有3个节点的链表的逻辑结构图。

 

图中的线太多,容易眼晕,下面这个图可能好一些。

 

转自:http://blog.csdn.net/livelylittlefish/article/details/6599065

技术选型 【后端】:Java 【框架】:springboot 【前端】:vue 【JDK版本】:JDK1.8 【服务器】:tomcat7+ 【数据库】:mysql 5.7+ 项目包含前后台完整源码。 项目都经过严格调试,确保可以运行! 具体项目介绍可查看博主文章或私聊获取 助力学习实践,提升编程技能,快来获取这份宝贵的资源吧! 在当今快速发展的信息技术领域,技术选型是决定一个项目成功与否的重要因素之一。基于以下的技术栈,我们为您带来了一份完善且经过实践验证的项目资源,让您在学习和提升编程技能的道路上事半功倍。以下是该项目的技术选型和其组件的详细介绍。 在后端技术方面,我们选择了Java作为编程语言。Java以其稳健性、跨平台性和丰富的库支持,在企业级应用中处于领导地位。项目采用了流行的Spring Boot框架,这个框架以简化Java企业级开发而闻名。Spring Boot提供了简洁的配置方式、内置的嵌入式服务器支持以及强大的生态系统,使开发者能够更高效地构建和部署应用。 前端技术方面,我们使用了Vue.js,这是一个用于构建用户界面的渐进式JavaScript框架。Vue以其易上手、灵活和性能出色而受到开发者的青睐,它的组件化开发思想也有助于提高代码的复用性和可维护性。 项目的编译和运行环境选择了JDK 1.8。尽管Java已经推出了更新的版本,但JDK 1.8依旧是一种成熟且稳定的选择,广泛应用于各类项目中,确保了兼容性和稳定性。 在服务器方面,本项目部署在Tomcat 7+之上。Tomcat是Apache软件基金会下的一个开源Servlet容器,也是应用最为广泛的Java Web服务器之一。其稳定性和可靠的性能表现为Java Web应用提供了坚实的支持。 数据库方面,我们采用了MySQL 5.7+。MySQL是一种高效、可靠且使用广泛的关系型数据库管理系统,5.7版本在性能和功能上都有显著的提升。 值得一提的是,该项目包含了前后台的完整源码,并经过严格调试,确保可以顺利运行。通过项目的学习和实践,您将能更好地掌握从后端到前端的完整开发流程,提升自己的编程技能。欢迎参考博主的详细文章或私信获取更多信息,利用这一宝贵资源来推进您的技术成长之路!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值