【nginx源码学习与运用 五】双向链表ngx_queue_t

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


在nginx中双向链表ngx_queue_t结构被大量使用,它单单只是一个双向链表,它不负责链表元素所占内存的分配,这种设计方法在linux内核中的结构设计中也常常使用,譬如linux内核的hash表结构、红黑树结构等等(有兴趣的鞋童可以翻看linux内核源码加以验证)。双向链表ngx_queue_t结构代码非常独立且与nginx的内存池完全无关,可以很轻松的提取到自己的代码中加以使用!

相关结构

struct ngx_queue_s {
    ngx_queue_t  *prev;
    ngx_queue_t  *next;
};

结构图

ngx_queue_t在不同状态下的结构体成员的值:
这里写图片描述

操作方法

容器所支持的方法

函数解释
ngx_queue_init初始化链表容器h
ngx_queue_empty检测链表容器是否为空
ngx_queue_insert_head将元素x插入到链表容器h的头部
ngx_queue_insert_tail将元素x插入到链表容器h的末尾
ngx_queue_head返回链表容器h中的第一个元素的ngx_queue_t结构体指针
ngx_queue_last返回链表容器h中的最后一个元素的ngx_queue_t结构体指针
ngx_queue_sentinel返回链表容器结构体的指针
ngx_queue_remove从容器中移除x元素
ngx_queue_split将链表h拆分成两个链表,q是h中的一个元素,n是h被拆开后的后半部分,q是n的首元素
ngx_queue_add合并链表,将n链表添加到h链表的尾部
ngx_queue_remove从容器中移除x元素
ngx_queue_split将链表h拆分成两个链表,q是h中的一个元素,n是h被拆开后的后半部分,q是n的首元素
ngx_queue_middle返回链表中心元素,即返回第N/2+1号元素,为链表元素总数
ngx_queue_sort使用插入法对链表进行排序,cmpfunc需要使用者自己实现,其原型为ngx_int_t (*cmpfunc)(const ngx_queue_t *, const ngx_queue_t *)

容器中元素所支持的方法

函数解释
ngx_queue_next返回h->next
ngx_queue_prev返回h->prev
ngx_queue_insert_after将元素x插入到元素h的后面
ngx_queue_data根据成员地址得到结构体首地址,q成员地址,type结构体类型,link成员名

使用方法与注意事项

  1. nginx提供给ngx_queue_t的操作方法几乎涵盖了双向链表的所有操作方法,不需要使用者另外使用自己创造的方法
  2. 对于ngx_queue_t结构体,必须调用ngx_queue_init进行初始化

示例代码

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"


typedef struct _testnode
{
    u_char *str;
    ngx_queue_t qEle;
    int num;
}TestNode;


ngx_int_t comTestNode(const ngx_queue_t *a, const ngx_queue_t *b)
{
    TestNode *aNode = ngx_queue_data(a, TestNode, qEle);
    TestNode *bNode = ngx_queue_data(b, TestNode, qEle);

    return aNode->num - bNode->num;
}

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

int main()
{
    int a = offsetof(TestNode, qEle);

    ngx_queue_t qc;
    ngx_queue_init(&qc);

    int i=0;
    TestNode node[5];
    for(; i<5; i++)
    {
        node[i].num = i;
        node[i].str = type_name[i];
    }

    ngx_queue_insert_tail(&qc, &node[0].qEle);
    ngx_queue_insert_head(&qc, &node[1].qEle);
    ngx_queue_insert_tail(&qc, &node[2].qEle);
    ngx_queue_insert_after(&qc, &node[3].qEle);
    ngx_queue_insert_tail(&qc, &node[4].qEle);  //想想此时双向链表中的数据顺序

    ngx_queue_t *q;
    TestNode *te;
    i = 0;
    PT_Info("beforce sort:\n");
    for(q = ngx_queue_head(&qc); q != ngx_queue_sentinel(&qc); q = ngx_queue_next(q))
    {
        te = ngx_queue_data(q, TestNode, qEle);
        PT_Info("the %d ele num:%d  str:%s\n", i, te->num, te->str);
        i++;
    }

    ngx_queue_sort(&qc, comTestNode);
    PT_Info("after sort:\n");
    i = 0;
    for(q = ngx_queue_head(&qc); q != ngx_queue_sentinel(&qc); q = ngx_queue_next(q))
    {
        te = ngx_queue_data(q, TestNode, qEle);
        PT_Info("the %d ele num:%d  str:%s\n", i, te->num, te->str);
        i++;
    }

}

运行结果

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值