nginx学习七 高级数据结构之动态数组ngx_array_t
1 ngx_array_t结构
ngx_array_t是nginx内部使用的数组结构。nginx的数组结构在存储上与大家认知的C语言内置的数组有相似性。比方实际上存储数据的区域也是一大块连续的内存。
可是数组除了存储数据的内存以外还包括一些元信息来描写叙述相关的一些信息,而且能够动态增长。以下
我们从数组的定义上来具体的了解一下。
ngx_array_t的定义位于src/core/ngx_array.c|h里面。
- struct ngx_array_s {
- void *elts;//数组的首地址
- ngx_uint_t nelts;//数组中已经使用的元素个数
- size_t size; //每一个元素占用的内存大小
- ngx_uint_t nalloc;//当前数组中可以容纳元素的个数
- ngx_pool_t *pool; //内存池对象
- };
elts指向存储数据内存的起始地址。
nelts是数组中实际已经存储的元素个数
size是每一个数组元素占用内存的大小。比方int占用4个字节的大小,size=4。
nalloc是数组空间大小。
pool成员函数负责管理数组使用的内存。
2函数操作
nginx为数组提供了五个操作函数例如以下:
//创建一个动态数组。数组的大小为n,每一个元素的大小为size
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
//销毁已分配的动态数组元素空间和动态数组对象
void ngx_array_destroy(ngx_array_t *a);
//向数组中加入一个元素,返回这个新元素的地址。假设数组空间已经用完,数组会自己主动扩充空间
void *ngx_array_push(ngx_array_t *a);
//向数组中加入n个元素,返回这n个元素中第一个元素的地址
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
//和create函数的功能差点儿相同,仅仅只是这个array不能为空,返回值为是否初始化成功
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
2.1ngx_array_create
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
创建一个数组,p是内存池对象, n为数组存储元素的个数, size为每一个元素占用的空间大小。
来看看源码:
- ngx_array_t *
- ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
- {
- ngx_array_t *a;
- //1:创建ngx_array_t指针。这个array的内存也是在p上申请的
- a = ngx_palloc(p, sizeof(ngx_array_t));
- if (a == NULL) {
- return NULL;
- }
- //2:申请数组存储元素的内存
- a->elts = ngx_palloc(p, n * size);
- if (a->elts == NULL) {
- return NULL;
- }
- //初始化成员
- a->nelts = 0;
- a->size = size;
- a->nalloc = n;
- a->pool = p;
- return a;//返回数组指针
- }
2.2 ngx_array_destroy
void ngx_array_destroy(ngx_array_t *a);
回收已分配给数组的内存,包含数组本身。看源码:
- void
- ngx_array_destroy(ngx_array_t *a)
- {
- ngx_pool_t *p;
- p = a->pool;
- //1:销毁数组存储元素的内存,即数据区的内存
- if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
- p->d.last -= a->size * a->nalloc;
- }
- //2:销毁数组本身的内存,即结构体array本身的内存
- //a = ngx_palloc(p, sizeof(ngx_array_t));这句代码申请的内存
- if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
- p->d.last = (u_char *) a;
- }
- }
2.3 ngx_array_push
void *ngx_array_push(ngx_array_t *a);
向数组中加入元素。而且返回新添加元素的地址。看源代码:
- void *
- ngx_array_push(ngx_array_t *a)
- {
- void *elt, *new;
- size_t size;
- ngx_pool_t *p;
- if (a->nelts == a->nalloc) {//数组已满
- size = a->size * a->nalloc;
- p = a->pool;
- if ((u_char *) a->elts + size == p->d.last
- && p->d.last + a->size <= p->d.end)//假设p的剩余空间>=一个数组元素的空间。就分配一个空间给数组
- {
- p->d.last += a->size;//调整pool的last。即改动下一次可分配空间的事实上地址
- a->nalloc++;
- } else {
- new = ngx_palloc(p, 2 * size);//申请新的空间,大小是原来的2倍,假如pool的内存不足够分配一个新的数组元素
- if (new == NULL) {
- return NULL;
- }
- ngx_memcpy(new, a->elts, size);//把原有的元素复制到新分配的内存区
- a->elts = new;//改动数组数据区的地址,使其指向新分配的内存区
- a->nalloc *= 2;//改动数组可容纳的元素个数,是原来容纳元素的2倍
- }
- }
- elt = (u_char *) a->elts + a->size * a->nelts;//新添加元素的地址
- a->nelts++;//数组中元素的个数加1
- return elt;//返回新添加元素的地址
- }
调用这个函数并没用真的加入进元素,它仅仅是返回新加元素将要被放入数组的地址,我们必须按例如以下操作才干真正的加入如元素:
- //加入一个int元素
- ngx_int_t* elem;
- elem = ngx_array_push(array);//得到新增元素地址
- *elem = 10;
2.4ngx_array_push_n
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
向数组中加入n个元素。返回这n个元素中第一个元素的地址。
- void *
- ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
- {
- void *elt, *new;
- size_t size;
- ngx_uint_t nalloc;
- ngx_pool_t *p;
- size = n * a->size;
- if (a->nelts + n > a->nalloc) {//数组已满
- p = a->pool;
- if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
- && p->d.last + size <= p->d.end)//假设pool剩余的内存可以容纳这n个元素,就不用又一次分配内存
- {
- p->d.last += size;//改动last使其指向可分配内存的起始地址
- a->nalloc += n;//数组容纳元素个数+n
- } else {//假设pool剩余的内存不可以容纳这n个元素。就又一次分配内存
- nalloc = 2 * ((n >= a->nalloc) ?
- n : a->nalloc);//申请2倍的内存
- new = ngx_palloc(p, nalloc * a->size);
- if (new == NULL) {
- return NULL;
- }
- ngx_memcpy(new, a->elts, a->nelts * a->size);//把原有的元素复制到新申请的内存中
- a->elts = new;//改动数组元素区的地址
- a->nalloc = nalloc;//改动数组可以容纳的元素个数
- }
- }
- elt = (u_char *) a->elts + a->size * a->nelts;//新增元素的首地址
- a->nelts += n;//已存储元素个数+n
- return elt;
- }
2.5 ngx_array_init
ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size);
和create函数的功能差点儿相同,仅仅只是这个array不能为空,返回值为是否初始化成功
- static ngx_inline ngx_int_t
- ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
- {
- /*
- * set "array->nelts" before "array->elts", otherwise MSVC thinks
- * that "array->nelts" may be used without having been initialized
- */
- //初始化array,array不能为空
- array->nelts = 0;
- array->size = size;
- array->nalloc = n;
- array->pool = pool;
- array->elts = ngx_palloc(pool, n * size);//申请内存空间
- if (array->elts == NULL) {
- return NGX_ERROR;
- }
- return NGX_OK;
- }
3 ngx_array_t的一个使用
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
- /*
- author: smtl
- date: 2014-09-28
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <ngx_core.h>
- #include <ngx_config.h>
- #include <ngx_conf_file.h>
- #include <nginx.h>
- #include <ngx_string.h>
- #include <ngx_palloc.h>
- #include <ngx_array.h>
- ////////////////////////////////////////////////////////////////////////////////////
- //不加以下这两个定义编译会出错
- volatile ngx_cycle_t *ngx_cycle;
- void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
- const char *fmt, ...)
- {
- }
- ////////////////////////////////////////////////////////////////////////////////////
- int main()//too many migical number
- {
- ngx_pool_t* pool = ngx_create_pool(2048, NULL);
- if (pool == NULL)
- {
- printf("create pool failed\n");
- exit(1);
- }
- ngx_array_t* array = ngx_array_create(pool, 20, sizeof(ngx_int_t));
- if (array == NULL)
- {
- printf("array alloc failed\n");
- exit(1);
- }
- ngx_int_t i;
- ngx_int_t* elem;
- for (i=0; i<20; ++i)
- {
- elem = ngx_array_push(array);//加入元素
- *elem = i;
- }
- elem = (int*)array->elts;
- for (i=0; i<20; ++i)
- {
- printf("array[%d] = %d \n", i, elem[i]);
- }
- printf("加入10个元素:\n");
- ngx_int_t n = 10;
- elem = ngx_array_push_n(array, n);
- for (i=0; i<n; ++i)
- {
- elem[i] = 20 + i;
- }
- elem = (int*)array->elts;
- for (i=20; i<20+n; ++i)
- {
- printf("array[%d] = %d \n", i, elem[i]);
- }
- ngx_array_destroy(array);
- printf("ngx_array_int:\n");
- array = ngx_pcalloc(pool, sizeof(ngx_array_t));
- //注意这个函数和ngx_array_create的差别。array不能为空
- ngx_array_init(array, pool, 20, sizeof(ngx_int_t));
- for (i=0; i<20; ++i)
- {
- elem = ngx_array_push(array);//加入元素
- *elem = rand()%1000;
- }
- elem = array->elts;
- for (i=0; i<20; ++i)
- {
- printf("array[%d] = %d \n", i, elem[i]);
- }
- ngx_destroy_pool(pool);
- return 0;
- }
nginx学习七 高级数据结构之动态数组ngx_array_t的更多相关文章
- nginx 学习八 高级数据结构之基数树ngx_radix_tree_t
1 nginx的基数树简单介绍 基数树是一种二叉查找树,它具备二叉查找树的全部长处:检索.插入.删除节点速度快,支持范围查找.支持遍历等. 在nginx中仅geo模块使用了基数树. nginx的基数树 ...
- nginx学习六 高级数据结构之双向链表ngx_queue_t
1 ngx_queue_t简单介绍 ngx_queue_t是nginx提供的一个轻量级的双向链表容器,它不负责存储数据,既不提供数据的内存分配.它仅仅有两个指针负责把数据链入链表.它跟stl提供的qu ...
- 菜鸟nginx源代码剖析数据结构篇(一)动态数组ngx_array_t
菜鸟nginx源代码剖析数据结构篇(一)动态数组ngx_array_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...
- 菜鸟nginx源码剖析数据结构篇(一)动态数组ngx_array_t[转]
菜鸟nginx源码剖析数据结构篇(一)动态数组ngx_array_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...
- (2)redis的基本数据结构是动态数组
redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; ]; }; 这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针, ...
- python数据结构之动态数组
数组列表:动态数组(Array List) 简介: 最基础简单的数据结构.最大的优点就是支持随机访问(O(1)),但是增加和删除操作效率就低一些(平均时间复杂度O(n)) 动态数组也称数组列表,在py ...
- JAVA数据结构--ArrayList动态数组
在计算机科学中,动态数组,可扩展数组,可调整数组,动态表,可变数组或数组列表是一种随机存取可变大小列表数据结构,允许添加或删除元素.它提供许多现代主流编程语言的标准库.动态数组克服了静态数组的限制,静 ...
- 高级数据结构(树状数组套主席树):ZOJ 2112 Dynamic Rankings
Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB The Company Dynamic Rankings has ...
- Nginx学习笔记(五):高级数据结构
目录 动态数组 单向链表 双端队列 红黑树 缓冲区 数据块链 键值对 动态数组 ngx_array_t 表示一块连续的内存,其中存放着数组元素,概念上和原始数组很接近 // 定义在 core/ng ...
随机推荐
- 【转】iOS手势识别的详细使用(拖动,缩放,旋转,点击,手势依赖,自定义手势) -- 不错不错
原文网址:http://blog.csdn.net/totogo2010/article/details/8615940 1.UIGestureRecognizer介绍 手势识别在iOS上非常重要,手 ...
- POJ 2828-Buy Tickets(线段树)
题意: 有n个人,每人有一定的价值,给n个安排,每次安排有两个数 p,v p是这个人前面人的个数 (直接插在第p个人后面其他人后移),v是它的价值,n个安排后 求最终的价值序列. 分析: 越在后面的安 ...
- java快速获取大图片的分辨率(大图片格式JPG,tiff ,eg)
问题描述:怎样快速获取一个20MB图片的分辨率? 程序代码: package test; import java.awt.Dimension; import java.awt.image.Buffer ...
- 《Python基础教程(第二版)》学习笔记 -> 第六章 抽象
抽象和结构 本章将会介绍如何让将语句组织成函数,还会详细介绍参数(parameter)和作用域(scope)的概念,以及递归的概念及其在程序中的用途. 创建函数 函数可以调用,它执行某种行为,并返回某 ...
- 【原】Storm 守护线程容错机制
Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Storm调度器 Storm配置 Guaranteeing Message Processing(消息处理 ...
- windows 下Python import 导入自定义模块
周末在家研究这个东西,则找到解决方案. 费话少说,上代码 #定义一个自定义的函数,如下 #函数的名称必须是字母和数字的组合,不能用数字开头 #函数名后用小括号括住入参,可以用逗号分隔多个 #如果有返回 ...
- cocos2d-x在NDK r9下的编译问题
:69: error: format not a string literal andno format arguments [-Werror=format-security]cc1plus.exe: ...
- SRM 599 DIV 2
rating又掉了...变灰色了%>_<%.250pt很简单,一眼看上去是个背包,没有多想立马写了个01背包,后面发现其实就是个简单的排序...因为只是需要求数量而已.500pt被我写残了 ...
- void类型及void指针
1.概述 许多初学者对C/C 语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并 详述void及void指针类型的使用方法与技巧. 2 ...
- [OC Foundation框架 - 21] NSSet集合 & 集合之间的转换
A.NSSet 跟NSArray一样,不可变 NSArray 自然顺序 NSSet是无序的 NSSet不允许存入重复元素,可以用来过滤重复元素 也有可变的NSMutableSet B.集合转换 ...