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


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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章