【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成员名 |
使用方法与注意事项
- nginx提供给ngx_queue_t的操作方法几乎涵盖了双向链表的所有操作方法,不需要使用者另外使用自己创造的方法
- 对于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++;
}
}
运行结果
截图如下: