【nginx源码学习与运用 四】单向链表ngx_list_t

【nginx源码学习与运用】系列博客中的示例代码在csdn的代码托管服务器CODE上,地址https://code.csdn.net/u012819339/nginx_study ,你可以将其自由的下载到本地,或者通过Git来实时获取更新

ngx_list_t说是单向链表,其实是链表和数组的结合体!!! 需仔细体会,链表中会存在不定数量的大小相同的定长数组,我们的节点元素其实是存储在数组中的,当数组被使用完了以后下次push操作会重新申请一个大小相同的数组追加到链表尾部!!


相关结构

ngx_list_t结构,描述整个链表

typedef struct {
    ngx_list_part_t  *last; //指向链表的最后一个数组元素
    ngx_list_part_t   part; //链表的首个数组元素
    size_t            size; //单个数组元素占用空间大小
    ngx_uint_t        nalloc; //表示每个ngx_list_part_t数组的容量
    ngx_pool_t       *pool; //所依附的内存池
} ngx_list_t;

ngx_list_part_t结构,描述链表的首个数组元素

struct ngx_list_part_s {
    void             *elts; //指向数组起始地址
    ngx_uint_t        nelts; //表示数组中已经使用了多少个元素,小于nalloc
    ngx_list_part_t  *next; //下一个链表元素ngx_list_part_t的地址
};

结构图

ngx_list_t 内存分布

这里写图片描述

操作方法

nginx的单项链表的操作方法比较少

函数解释
ngx_list_create创建并初始化含有一个数组的链表,该数组元素有n个元素,每个成元素用size大小的空间
ngx_list_push向后移动一个元素位置,用于存储元素信息,(如果当前数组使用已满,则会向内存池申请一个数组元素并追加到链表尾部,这个数组元素和链表首部数组大小相同),返回用于存储元素的地址

使用方法与注意事项

1.ngx_list_create初始化一个链表,向内存池预先申请一定的数组存储空间,但当前并没有开始使用链表
2.ngx_list_push每做一次push,链表就会腾出一个空间来存储元素,如果当前链表数组存储空间已满,则会向内存池再次申请一个同样大小的数组空间
3. nginx没有提供list的遍历函数,但是nginx有推荐的遍历链表的方式,看如下代码片段:

/*
 *
 *  the iteration through the list:
 *
 *  part = &list.part;
 *  data = part->elts;
 *
 *  for (i = 0 ;; i++) {
 *
 *      if (i >= part->nelts) {
 *          if (part->next == NULL) {
 *              break;
 *          }
 *
 *          part = part->next;
 *          data = part->elts;
 *          i = 0;
 *      }
 *
 *      ...  data[i] ...
 *
 *  }
 */

示例代码

arvik将nginx中的部分基础结构代码提出来了,好作为新手学习练习使用。见 https://code.csdn.net/u012819339/nginx_study
main.c

/*
blog:   http://blog.csdn.net/u012819339
email:  1216601195@qq.com
author: arvik
*/

#include <stdio.h>
#include <string.h>
#include "ak_core.h"
#include "pt.h"

struct node_s
{
    int index;
    char *name;
};

char *type_name[] = 
{
    "jame",
    "arvik",
    "rose",
    "tom",
    "jack"
};

int main()
{
    ngx_pool_t *p;
    struct node_s *s1, *s2;
    int i = 0;

    p = ngx_create_pool(1000); 
    if(p == NULL)
        return -1;

    ngx_list_t *my_list = ngx_list_create(p, 3, sizeof(struct node_s));
    if(my_list == NULL)
        return -1;

    for(i=0; i<5; i++)
    {
        s2 = ngx_list_push(my_list);  //童鞋们在此思考一下,此处每次push之后,链表的总长度为多少?实际使用长度为多少? 
        s2->name = type_name[i];
        s2->index = i;
    }

    PT_Info("list ele info:\n");
    //nginx推荐的遍历操作方法
    ngx_list_part_t *part = &my_list->part;
    s1 = (struct node_s *)part->elts;
    for( i = 0; ; i++)
    {
        if(i >= part->nelts)
        {
            if(part->next == NULL)
                break;

            part = part->next;
            s1 = part->elts;
            i = 0;
        }

        PT_Info("ele name:%s    index:%d\n", s1[i].name, s1[i].index );
    }

    ngx_destroy_pool(p);
}

运行结果

截图如下:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值