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;
}

http://blog.csdn.net/xiaoliangsky/article/details/39647771

nginx学习七 高级数据结构之动态数组ngx_array_t的更多相关文章

  1. nginx 学习八 高级数据结构之基数树ngx_radix_tree_t

    1 nginx的基数树简单介绍 基数树是一种二叉查找树,它具备二叉查找树的全部长处:检索.插入.删除节点速度快,支持范围查找.支持遍历等. 在nginx中仅geo模块使用了基数树. nginx的基数树 ...

  2. nginx学习六 高级数据结构之双向链表ngx_queue_t

    1 ngx_queue_t简单介绍 ngx_queue_t是nginx提供的一个轻量级的双向链表容器,它不负责存储数据,既不提供数据的内存分配.它仅仅有两个指针负责把数据链入链表.它跟stl提供的qu ...

  3. 菜鸟nginx源代码剖析数据结构篇(一)动态数组ngx_array_t

    菜鸟nginx源代码剖析数据结构篇(一)动态数组ngx_array_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...

  4. 菜鸟nginx源码剖析数据结构篇(一)动态数组ngx_array_t[转]

    菜鸟nginx源码剖析数据结构篇(一)动态数组ngx_array_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...

  5. (2)redis的基本数据结构是动态数组

    redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; ]; }; 这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针, ...

  6. python数据结构之动态数组

    数组列表:动态数组(Array List) 简介: 最基础简单的数据结构.最大的优点就是支持随机访问(O(1)),但是增加和删除操作效率就低一些(平均时间复杂度O(n)) 动态数组也称数组列表,在py ...

  7. JAVA数据结构--ArrayList动态数组

    在计算机科学中,动态数组,可扩展数组,可调整数组,动态表,可变数组或数组列表是一种随机存取可变大小列表数据结构,允许添加或删除元素.它提供许多现代主流编程语言的标准库.动态数组克服了静态数组的限制,静 ...

  8. 高级数据结构(树状数组套主席树):ZOJ 2112 Dynamic Rankings

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  9. Nginx学习笔记(五):高级数据结构

    目录 动态数组 单向链表 双端队列 红黑树 缓冲区 数据块链 键值对   动态数组 ngx_array_t 表示一块连续的内存,其中存放着数组元素,概念上和原始数组很接近 // 定义在 core/ng ...

随机推荐

  1. lnmp 安装环境之后discuz论坛排版乱的问题

    服务器系统类型:centos 6.5 环境:使用lnmp官方安装shell安装 (http://lnmp.org/install.html) 在部署dz之后,访问页面 出现排版乱,资源不能加载的问题: ...

  2. 浅谈JavaBean,Entity Bean,Enterprise Bean等Bean以及POJO的含义

      一.对于java bean,就是一个java模型组件,他为使用java类提供了一种标准的格式,在用户程序和可视化管理工具中可以自动获得这种具有标准格式的类的信息,并能够创建和管理这些类.  jav ...

  3. 真机无法接收到android.provider.Telephony.SMS_RECEIVED的问题

    小米2S有一个设定会导致,App无法接收到android.provider.Telephony.SMS_RECEIVED广播. 解决方案 关闭系统短信优先设置 短信-设置-高级设置-系统短信优先   ...

  4. 新手!SDK Manager里找不到API安装的选项怎么办?

    只有Tools和EXTRAS文件夹的选项,没有API包安装,咋办呢?   回复讨论(解决方案) 网络有问题吗? 网络有问题吗? 就是不知道啊 你是在eclispe里面打开的?还是在外面直接打开的?没有 ...

  5. POJ 2243 Knight Moves

    Knight Moves Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13222   Accepted: 7418 Des ...

  6. 并发编程之--ConcurrentSkipListMap

    概要 本章对Java.util.concurrent包中的ConcurrentSkipListMap类进行详细的介绍.内容包括:ConcurrentSkipListMap介绍ConcurrentSki ...

  7. VTL说明文档

    关于这个指南 这个指南是针对Velocity模版语言(VTL)的说明.更多其它的信息,请参考Velocity用户指南(http://velocity.apache.org/engine/release ...

  8. 二维坐标的平移,旋转,缩放及matlab实现

    本文结合matlab 软件解释二维坐标系下的平移,旋转,缩放 首先确定点在二维坐标系下的表达方法,使用一个1*3矩阵: Pt = [x,y,1] 其中x,y 分别为点的X,Y坐标,1为对二维坐标的三维 ...

  9. MyEclipse10 Tomcat7 JDK1.7 配置

    第一步.MyEclipse10 Tomcat7 JDK1.7下载 MyEclipse10http://downloads.myeclipseide.com/downloads/products/ewo ...

  10. 项目用到了lua的哪些部分

    昨天有位同事跟我说,我们的手游客户端(cocos2d-x lua binding)代码没有看到lua的特殊技巧,用起来跟其他语言差不多.<Programming in lua>毕竟有将近4 ...