ChianXu 发表于 2011-12-22 08:54

nginx数据结构之list

<DIV>nginx 的链表的定义在core/ngx_list.h中:<BR>typedef struct {<BR>&nbsp;&nbsp;&nbsp; ngx_list_part_t&nbsp; *last;&nbsp;&nbsp;&nbsp;&nbsp; //最后一块<BR>&nbsp;&nbsp;&nbsp; ngx_list_part_t&nbsp;&nbsp; part;&nbsp;&nbsp;&nbsp;&nbsp; //第一块<BR>&nbsp;&nbsp;&nbsp; size_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //元素大小<BR>&nbsp;&nbsp;&nbsp; ngx_uint_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nalloc;&nbsp;&nbsp; //每块可存的元素个数<BR>&nbsp;&nbsp;&nbsp; ngx_pool_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pool;&nbsp;&nbsp; //内存池<BR>} ngx_list_t;<BR><BR>nginx 的链表和传统的链表不同,不是将<B>每个</B>元素通过指针连接起来,而是将<B>每块</B>元素通过指针连接起来。<BR>链表块的定义如下:<BR>struct ngx_list_part_s {<BR>&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *elts;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //元素所在内存<BR>&nbsp;&nbsp;&nbsp; ngx_uint_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nelts;&nbsp;&nbsp;&nbsp;&nbsp; //已经存储的元素个数<BR>&nbsp;&nbsp;&nbsp; ngx_list_part_t&nbsp; *next;&nbsp;&nbsp;&nbsp; //下一块<BR>};<BR>
<DIV><IMG style="MARGIN: 0pt 10px 0pt 0pt" alt="nginx的数据结构(2) 链表ngx_list_s - hankjin - 云水居" src="http://img762.ph.126.net/W4Je8W9P-g8CKaYDwosBhg==/4947485665643323940.png" __1312281485406__="ev_6093348017"></DIV>上图的ngx_list包含四个块,共 3*n+m 个元素。注意,只有最后一个块才可能处于不満状态,因为和 ngx_array 一样,ngx_list 也没有定义元素删除操作。甚至ngx_list连整个链表销毁的操作也没定义。<BR>&nbsp;<BR>链表结构内包含第一个块,以及最后一个块的指针。<BR><B>1。创建链表:</B><BR>创建链表主要是申请两块内存,初始化一些变量:<BR>申请ngx_list_t,因为ngx_list_t中包括一个ngx_list_part,所以申请ngx_list_t的同时也申请到了一个ngx_list_part<BR>申请ngx_list_part的元素数组的内存<BR>代码如core/ngx_list.c的ngx_list_create所示<BR>&nbsp;&nbsp;&nbsp; list = ngx_palloc(pool, sizeof(ngx_list_t));//申请ngx_list_t内存<BR>&nbsp;&nbsp;&nbsp; list-&gt;part.elts = ngx_palloc(pool, n * size);//申请元素数组的内存(元素个数*每个元素的大小)<BR>&nbsp;&nbsp;&nbsp; list-&gt;part.nelts = 0;//已存0个元素<BR>&nbsp;&nbsp;&nbsp; list-&gt;part.next = NULL;//只有一个块<BR>&nbsp;&nbsp;&nbsp; list-&gt;last = &amp;list-&gt;part;//最后一个块即为当前块<BR>&nbsp;&nbsp;&nbsp; list-&gt;nalloc = n;//可存的元素个数<BR><BR><B>2。加入元素:<BR></B>加入元素时,首先根据ngx_list_t的last指针定位最后一块,<BR>然后检测最后一块的元素是否已经用完了,ngx_list_part_t-&gt;nelts == ngx_list_t-&gt;nalloc<BR>如果没満,则将最后一块的第nelts元素返回即可。<BR>代码如core/ngx_list.c的ngx_list_push所示:<BR>&nbsp;&nbsp;&nbsp; elt = (char *) last-&gt;elts + l-&gt;size * last-&gt;nelts; //空闲元素位置<BR>&nbsp;&nbsp;&nbsp; last-&gt;nelts++; //已存储的元素个数+1<BR>如果满了,则申请一个新的链表块,并加入链<BR>if (last-&gt;nelts == l-&gt;nalloc) {//如果最后一个块的元素已经用完了<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last = ngx_palloc(l-&gt;pool, sizeof(ngx_list_part_t)); //申请一个块结构<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last-&gt;elts = ngx_palloc(l-&gt;pool, l-&gt;nalloc * l-&gt;size);//申请新块的元素数组<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last-&gt;nelts = 0;//初始化新块<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last-&gt;next = NULL;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l-&gt;last-&gt;next = last;//将新块加入链表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l-&gt;last = last;//修改链表的last指针,让其指向新申请的块<BR>然后再定位并返回元素。<BR><BR><B>3。遍历链表:<BR></B>nginx 链表的与众不同导致其遍历方式也与一般链表不同。<BR>要遍历每个块的每个元素,需要维护两个指针和一个下标:当前块指针,当前元素指针和当前元素下标<BR>常见的nginx链表访问方式如下所示:<BR>//core/ngx_cycle.c中的ngx_init_cycle函数中对file的操作部分<BR>&nbsp;&nbsp;&nbsp; part = mylist-&gt;part;//块指针初始化为第一块<BR>&nbsp;&nbsp;&nbsp; ele = part-&gt;elts; //元素指针初始化为元素指针<BR>&nbsp;&nbsp;&nbsp; for (i = 0; /* void */ ; i++) { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i &gt;= part-&gt;nelts) {//当前块遍历完成<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (part-&gt;next == NULL) {//如果没有其它块,则退出循环<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; part = part-&gt;next;//当前块指向下一块<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ele = part-&gt;elts; //修改当前块的元素指针<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = 0; //修改元素指针的下标<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <BR><B>优点</B>:<BR>ngx_list 采用分块的方式进行内存管理,确实在很大程度上降低了从内存池申请内存的频率,对性能提升有较好的帮助。<BR>但分块的特点也决定了元素删除操作较难处理,而ngx_list没有定义删除操作,难道是因为这个原因?<BR>nginx 定义了还定义了队列 ngx_queue 的数据结构, 与 ngx_list 相比,ngx_queue 更像链表。可以说 ngx_list 是一种比较特殊的链表:块链表。</DIV>
<DIV>&nbsp;</DIV>
<DIV>本文摘自:<a href="http://hankjin.blog.163.com/blog/static/33731937201091111303630/" target="_blank">http://hankjin.blog.163.com/blog/static/33731937201091111303630/</A>感谢作者的辛勤成果</DIV>
页: [1]
查看完整版本: nginx数据结构之list