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