1、數據結構
struct ngx_array_s {
void *elts; //數組數據區起始位置
ngx_uint_t nelts; //實際已存放的元素個數
size_t size; //每個元素大小,可用sizeof獲得大小
ngx_uint_t nalloc; //數組所含空間個數,即實際分配的小空間的個數
ngx_pool_t *pool; //該數組在此內存池中分配
};
nginx封裝了非常好用的數組ngx_array_t,在做nginx模塊開發的時候,就不必再使用原始的數組了,這個數組是可以動態擴展的,也可以稱爲“動態數組”。每個數據項的具體含義是:
(1)elts:指向一塊向系統申請的內存,在nginx中,這塊內存通過palloc或其它操作從內存池申請而來;
(2)nelts:記錄數組中已存放元素的個數;
(3)size:數組元素的大小,可以通過sizeof()求的;
(4)nalloc:整個數組可存放元素的單元數;
(5)pool:內存池,用其保存分配此數組的內存池地址;
備註:sizeof(ngx_array_t)=20,則表明nginx的數組也要從內存池中分配,將分配nalloc個大小爲size的小空間,實際分配空間爲elts=nalloc*size。
2、數組操作
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
函數功能:用來創建一個可以存儲n個元素,每個元素大小爲size的數組,返回值是維護數組的結構的地址。
ngx_array_t *< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
{
ngx_array_t *a;
a = ngx_palloc(p, sizeof(ngx_array_t)); //從內存池中分配數組頭
if (a == NULL) {
return NULL;
}
a->elts = ngx_palloc(p, n * size); //分配n*size大小的區域作爲數組數據區
if (a->elts == NULL) {
return NULL;
}
a->nelts = 0; //初始化爲0,表示已存放元素
a->size = size;
a->nalloc = n;
a->pool = p;
return a;
}
ngx_array_destroy(ngx_array_t *a);
函數功能:銷燬數組主要包括銷燬數組數據區和數組頭,這裏的銷燬動作實際上就是修改內存池的last指針,並沒有真正調用free等釋放內存的操作,而是將內存歸還給內存池。
void
ngx_array_destroy(ngx_array_t *a)
{
ngx_pool_t *p;
p = a->pool;
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) { //銷燬數組數據區
p->d.last -= a->size * a->nalloc;
}
if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) { //銷燬數組頭部
p->d.last = (u_char *) a;
}
}
ngx_array_push(ngx_array_t *a);
函數功能:此函數的功能就是取得下一個可以存放元素的單元地址。此接口函數是nginx模塊開發中,使用最多的數組操作接口了。由於nginx封裝的數組可以根據需求動態擴展,所以此函數必須處理預分配的內存不足的情況。nginx在ngx_array_push函數內存採用了兩種策略來動態增加內存。
(1)預分配的內存不足了,但數組所在的內存池槽還有可以分配一個元素的空閒內存,那就在數組末端分配一個元素的空間來暫時滿足當前需求。
(2)預分配的內存不足,同時數組所在的內存池槽的空閒內存也不足以分配一個元素的空間了,那就向內存池申請一個原數組2倍大小的新內存空間,再將原數組複製到新的位置,最後返回下一個空閒元素位置給我們使用。
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 //若內存池的last指針指向數組數據區的末尾
&& p->d.last + a->size <= p->d.end) //且內存池未使用的區域可以再分配一個size大小的小空間
{
p->d.last += a->size;
a->nalloc++; //實際分配小空間的個數+1
} else {
new = ngx_palloc(p, 2 * size); //重新申請新的數組數據區
if (new == NULL) {
return NULL;
}
ngx_memcpy(new, a->elts, size); //複製原來數據區的內容
a->elts = new;
a->nalloc *= 2;
}
}
elt = (u_char *) a->elts + a->size * a->nelts;
a->nelts++;
return elt; //返回該末尾指針,即下個元素應該存放的位置
}
函數常用方法:
typedef struct {
int age;
char *name;
} person_t;
person_t *p = ngx_array_push(a); //先分配內存
p->age = 23; //初始化
p->name = (char *)"marcky";
備註:向數組中添加元素實際上是修改內存池的last指針及數組頭信息,即使數組已滿,需要擴展數據區內容,也只需要內存拷貝完成,並不需要數據的移動操作,內存拷貝的效率是相當高的。
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
函數功能:用來獲得n個元素的內存空間地址,然後從獲得的地址向數組中填入n個元素。
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
函數功能:初始化數組,ngx_array_init和ngx_array_create的主要區別是ngx_array_init只初始化數組數據區,而ngx_array_create不僅要初始化數組數據區,還要初始化數組頭部信息。
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
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、使用實例
typedef struct {
int age;
char name[256];
} person_t;
ngx_array_t *datas;
person_t *node;
datas = ngx_array_create(pool, 10, sizeof(person_t)); //創建數組
if (datas == NULL){
return NGX_ERROR;
}
node = (person_t *)ngx_array_push(datas); //取得下一個可以存放元素的單元地址
node->age = 16; //填充數據
strcpy(node->name, ”chenjie”, strlen(“chenjie”));
node->name[strlen(“chenjie”)]=0;