【nginx源码学习与运用】系列博客中的示例代码在csdn的代码托管服务器CODE上,地址https://code.csdn.net/u012819339/nginx_study ,你可以将其自由的下载到本地,或者通过Git来实时获取更新
ngx_list_t说是单向链表,其实是链表和数组的结合体!!! 需仔细体会,链表中会存在不定数量的大小相同的定长数组,我们的节点元素其实是存储在数组中的,当数组被使用完了以后下次push操作会重新申请一个大小相同的数组追加到链表尾部!!
相关结构
ngx_list_t
结构,描述整个链表
typedef struct {
ngx_list_part_t *last; //指向链表的最后一个数组元素
ngx_list_part_t part; //链表的首个数组元素
size_t size; //单个数组元素占用空间大小
ngx_uint_t nalloc; //表示每个ngx_list_part_t数组的容量
ngx_pool_t *pool; //所依附的内存池
} ngx_list_t;
ngx_list_part_t结构,描述链表的首个数组元素
struct ngx_list_part_s {
void *elts; //指向数组起始地址
ngx_uint_t nelts; //表示数组中已经使用了多少个元素,小于nalloc
ngx_list_part_t *next; //下一个链表元素ngx_list_part_t的地址
};
结构图
ngx_list_t 内存分布
操作方法
nginx的单项链表的操作方法比较少
函数 | 解释 |
---|---|
ngx_list_create | 创建并初始化含有一个数组的链表,该数组元素有n个元素,每个成元素用size大小的空间 |
ngx_list_push | 向后移动一个元素位置,用于存储元素信息,(如果当前数组使用已满,则会向内存池申请一个数组元素并追加到链表尾部,这个数组元素和链表首部数组大小相同),返回用于存储元素的地址 |
使用方法与注意事项
1.ngx_list_create
初始化一个链表,向内存池预先申请一定的数组存储空间,但当前并没有开始使用链表
2.ngx_list_push
每做一次push,链表就会腾出一个空间来存储元素,如果当前链表数组存储空间已满,则会向内存池再次申请一个同样大小的数组空间
3. nginx没有提供list的遍历函数,但是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] ...
*
* }
*/
示例代码
arvik将nginx中的部分基础结构代码提出来了,好作为新手学习练习使用。见 https://code.csdn.net/u012819339/nginx_study
main.c
/*
blog: http://blog.csdn.net/u012819339
email: 1216601195@qq.com
author: arvik
*/
#include <stdio.h>
#include <string.h>
#include "ak_core.h"
#include "pt.h"
struct node_s
{
int index;
char *name;
};
char *type_name[] =
{
"jame",
"arvik",
"rose",
"tom",
"jack"
};
int main()
{
ngx_pool_t *p;
struct node_s *s1, *s2;
int i = 0;
p = ngx_create_pool(1000);
if(p == NULL)
return -1;
ngx_list_t *my_list = ngx_list_create(p, 3, sizeof(struct node_s));
if(my_list == NULL)
return -1;
for(i=0; i<5; i++)
{
s2 = ngx_list_push(my_list); //童鞋们在此思考一下,此处每次push之后,链表的总长度为多少?实际使用长度为多少?
s2->name = type_name[i];
s2->index = i;
}
PT_Info("list ele info:\n");
//nginx推荐的遍历操作方法
ngx_list_part_t *part = &my_list->part;
s1 = (struct node_s *)part->elts;
for( i = 0; ; i++)
{
if(i >= part->nelts)
{
if(part->next == NULL)
break;
part = part->next;
s1 = part->elts;
i = 0;
}
PT_Info("ele name:%s index:%d\n", s1[i].name, s1[i].index );
}
ngx_destroy_pool(p);
}
运行结果
截图如下: