由Nginx源码写双向循环链表
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
Nginx提供了轻量级的双向链表,仅有指针域,而无数据域.用户在使用的时候需要自定义一个包含了这个指针域的结构体,其指针域定义如下:
typedef struct ngx_queue_s ngx_queue_t;struct ngx_queue_s {ngx_queue_t *prev; // 前置指针域ngx_queue_t *next; // 后置指针域
};
用户使用的图示:
大概扫了一眼实现的源码,看了下风格,我模仿它写了一个双向循环链表.
初始化
提示:
方法名: ngx_queue_init(h)
参数含义: h为链表容器结构体ngx_queue_t的指针
执行意义: 将链表容器初始化,这时会自动置为空链表
#define ngx_queue_init(q) \(q) -> prev = q; \(q) -> next = q;
判空
提示:
方法名: ngx_queue_empty(h)
参数含义: h为链表容器结构体ngx_queue_t的指针
执行意义: 检测链表容器中是否为空,即是否没有一个元素存在.如果返回非0,表示链表h是空的.
#define ngx_queue_empty(q) \(q == (q) -> prev)
插入元素
此处使用的思想正如我在之前的《单链表》一文中写的链表插入的思想,归纳为八个字:先斩后奏,先左后右.传送链接:单链表
提示:
方法名: ngx_queue_insert_head(h,x)
参数含义: h为链表容器结构体ngx_queue_t的指针,x为插入元素结构体中ngx_queue_t成员的指针
执行意义: 将元素x插入到链表容器h的头部
#define ngx_queue_insert_head(q,x) \(x) -> prev = q; \(x) -> next = (q) -> next; \(q) -> next -> prev = x; \(q) -> next = x;
提示:
方法名: ngx_queue_insert_tail(h,x)
参数含义: h为链表容器结构体ngx_queue_t的指针,x为插入元素结构体中ngx_queue_t成员的指针
执行意义: 将元素x插入到链表容器h的末尾
#define ngx_queue_insert_tail(q,x) \(x) -> prev = (q) -> prev; \(x) -> next = q; \(q) -> prev -> next = x; \(q) -> prev = x;
查找
提示:
方法名: ngx_queue_head(h)
参数含义: h为链表容器结构体ngx_queue_t的指针
执行意义: 返回链表容器h中的第一个元素的ngx_queue_t结构体指针
#define ngx_queue_head(q) \(q) -> next
提示:
方法名: ngx_queue_last(h)
参数含义: h为链表容器结构体ngx_queue_t的指针
执行意义: 返回链表容器h中的最后一个元素的ngx_queue_t结构体指针
#define ngx_queue_last(q) \(q) -> prev
提示:
方法名: ngx_queue_next(q)
参数含义: q为链表中某一个元素结构体的ngx_queue_t成员的指针
执行意义: 返回q元素的下一个元素
#define ngx_queue_next(q) \(q) -> next
提示:
方法名: ngx_queue_prev(q)
参数含义: q为链表中某一个元素结构体的ngx_queue_t成员的指针
执行意义: 返回q元素的上一个元素
#define ngx_queue_prev(q) \(q) -> prev
删除
提示:
方法名: ngx_queue_remove(x)
参数含义: x为插入元素结构体中ngx_queue_t成员的指针
执行意义: 由容器中移除x元素
#define ngx_queue_remove(x) \(x) -> prev -> next = (x) -> next; \(x) -> next -> prev = (x) -> prev;
寻址
提示:
方法名: ngx_queue_data(q, type, link)
参数含义: q为链表中某一个元素结构体中ngx_queue_t成员的指针,type为链表元素的结构体类型名称(该结构体中必须包含ngx_queue_t类型的成员),link是上面这个结构体重ngx_queue_t类型的成员名字
执行意义: 返回q元素(ngx_queue_t类型)所属结构体(任何struct类型,其中可在任意位置包含ngx_queue_t类型的成员)的地址
#define ngx_queue_data(q, type, link) \(type *)((unsigned char *)q - offsetof(type, link))
这里用到了offsetof这个宏.
C 库宏 offsetof(type, member-designator) 会生成一个类型为 size_t 的整型常量,它是一个结构成员相对于结构开头的字节偏移量。成员是由 member-designator 给定的,结构的名称是在 type 中给定的。
全部代码及测试代码
这里只测试了部分宏函数.
#include <iostream>using namespace std;typedef struct ngx_queue_s ngx_queue_t;struct ngx_queue_s {ngx_queue_t *prev; // 前置指针域ngx_queue_t *next; // 后置指针域
};#define ngx_queue_init(q) \(q) -> prev = q; \(q) -> next = q;#define ngx_queue_empty(q) \(q == (q) -> prev)#define ngx_queue_insert_head(q,x) \(x) -> prev = q; \(x) -> next = (q) -> next; \(q) -> next -> prev = x; \(q) -> next = x;#define ngx_queue_insert_tail(q,x) \(x) -> prev = (q) -> prev; \(x) -> next = q; \(q) -> prev -> next = x; \(q) -> prev = x;#define ngx_queue_head(q) \(q) -> next#define ngx_queue_last(q) \(q) -> prev#define ngx_queue_remove(x) \(x) -> prev -> next = (x) -> next; \(x) -> next -> prev = (x) -> prev;#define ngx_queue_next(q) \(q) -> next#define ngx_queue_prev(q) \(q) -> prev#define ngx_queue_data(q, type, link) \(type *)((unsigned char *)q - offsetof(type, link))typedef struct {ngx_queue_t p;int data;
}User;//用户自定义结构体void printNginx(ngx_queue_t *node) {ngx_queue_t *e = ngx_queue_head(node);//第一个结点while (e != node) {User *node = ngx_queue_data(e, User, p);//寻址cout << node->data << "\t";e = ngx_queue_next(e);}cout << endl;
}int main(void) {User *user=new User;ngx_queue_t *head = &(user->p);//头结点ngx_queue_init(head);if (ngx_queue_empty(head)) {cout << "链表为空!" << endl;}int n;cout << "请输入插入元素的个数(正在使用头插法):";cin >> n;while (n--) {User *node=new User;ngx_queue_t *e = &(node->p);cout << "请输入元素的数据:";cin >> node->data;ngx_queue_insert_head(head, e);}printNginx(head);system("pause");return 0;
}
事实上,在写测试代码的时候相当困难,中间改写了很多次,其根本原因是不熟悉其体现的思想.不过好在多次思考,断点调试,揣摩代码,最终才有了这篇文章.
由Nginx源码写双向循环链表相关推荐
- Nginx源码分析-内存池
本文转自淘宝平台http://www.tbdata.org/archives/1390,不是为了夺他人之美,只是觉得写得很好,怕淘宝万一删掉就找不到了,放在这里保存一下.大家可以直接链接过去,他们那个 ...
- 从Nginx源码谈大小写字符转化的最高效代码以及ASCII码表的科学
说起大小写字母转换,大家很容易想起系统函数是不是,几乎所有的编程语言都提供了这种转换函数,但是你有没有想过这背后是怎么实现的? 让你写怎么实现? 我们都知道Nginx是目前用的最多的Http服务器,那 ...
- Nginx源码分析--数据对齐posix_memalign和memalign函数
posix_memalign函数() /* * 背景: * 1)POSIX 1003.1d * 2)POSIX 标明了通过malloc( ), calloc( ), 和 re ...
- Nginx源码分析:epoll事件处理模块概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 事件处理模块概述 Nginx的高效请求的处理依赖于事件管理机制,本次默认的场景是Linux操 ...
- Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...
- 设计模式在C语言中的应用--读nginx源码
市面上的"设计模式"书籍文章,皆针对Java/C++/C#等面向对象语言,似乎离开了面向对象的种种特性,设计模式就无法实现,没有用武之地了. 是这样吗?设计模式的概念是从建筑领域引 ...
- nginx源码分析—内存池结构ngx_pool_t及内存管理
本博客( http://blog.csdn.net/livelylittlefish)贴出作者(阿波)相关研究.学习内容所做的笔记,欢迎广大朋友指正! Content 0.序 1.内存池结构 1.1 ...
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一
搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置.那么nginx 以模块 module为骨架的设计下是如何运用模 ...
- nginx 源码调试
nginx 源码调试 这段时间正在学习nginx源码,看到一贴子的提问 (帖子:http://www.oschina.net/question/2711991_2165566?p=1#AnchorAn ...
最新文章
- 广东电大计算机绘图试题,电大计算机绘图期末复习试题及答案参考小抄.doc
- Windows 7 RC Build 7100 使用报告
- Theme.NoTitleBar问题
- swiper 在turn.js不能滚动
- python截图识别文字_用百度ocr+微信截图实现文字识别
- Ribbon和Feign的对比-带简易例子
- SQL server 數據庫 從SQL2000搬移到SQL2016
- 微信语音红包小程序开发如何提高精准度 红包小程序语音识别精准度 微信小程序红包开发语音红包...
- 扩展欧几里得算法的讲解
- 计算机及数码产品营销课后题,职业教育课程改革创新系列教材:计算机及数码产品营销...
- 开启win10隐藏语音库
- 设置linux kernel 日志打印方法
- flutter floor数据库框架使用
- 2022软件测试自学路线分享,附完整资料,自学也能拿高薪哟
- 【论文导读】Causal Protein-Signaling Networks Derived from Multiparameter Single-Cell Data
- jni使用(四)-----IDEA中javah生成.h文件
- 【达摩院OpenVI】AIGC技术在图像超分上的创新应用
- Air724UG HCore-A724UG YunDTU固件
- [Paper Reading] Towards Conversational Recommendation over Multi-Type Dialogs
- Install xe-guest-utilities in PfSense 2.3