Nginx-ngx_queue
来源:互联网 发布:级域名泛解析多久生效 编辑:程序博客网 时间:2024/04/24 04:04
这一篇是要介绍一个常见的数据结构——队列,来看看nginx中是怎么实现的队列,先来看看队列的数据结构定义。
typedef struct ngx_queue_s ngx_queue_t;struct ngx_queue_s { ngx_queue_t *prev; ngx_queue_t *next;};nginx中实现的queue有两个特点:
1, 队列节点没有数据区,这是为了更好的抽像队列这个基础数据结构,ngx_queue_t这结构体是被封装到其他结构体中,这样来实现队列的功能。
2,实际上队列实现的是一个循环队列,其中有一个哨兵结点来连接首尾节点。
从.h文件中可以看到关于队列的大量操作都是以宏定义的形式来实现的。各个宏的解释建下面代码中的注释。
//初始化队列哨兵结点,注意哨兵结点是不涉及到任何数据字段的,它只是一个首尾节点连接器define ngx_queue_init(q) \ (q)->prev = q; \ (q)->next = q//判断队列是否为空,如果哨兵节点和它的前一个节点指针一样,那么久没有数据节点#define ngx_queue_empty(h) \ (h == (h)->prev)//将节点x加入到队列并作为第一个节点#define ngx_queue_insert_head(h, x) \ (x)->next = (h)->next; \ (x)->next->prev = x; \ (x)->prev = h; \ (h)->next = x#define ngx_queue_insert_after ngx_queue_insert_head//将节点x加入到队列,并作为最后一个节点#define ngx_queue_insert_tail(h, x) \ (x)->prev = (h)->prev; \ (x)->prev->next = x; \ (x)->next = h; \ (h)->prev = x//获取队列的第一个节点#define ngx_queue_head(h) \ (h)->next//获取队列的最后一个节点#define ngx_queue_last(h) \ (h)->prev//获取哨兵节点#define ngx_queue_sentinel(h) \ (h)//获取当前节点的下一个节点#define ngx_queue_next(q) \ (q)->next//获取当前节点的前一个节点#define ngx_queue_prev(q) \ (q)->prev#if (NGX_DEBUG)#define ngx_queue_remove(x) \ (x)->next->prev = (x)->prev; \ (x)->prev->next = (x)->next; \ (x)->prev = NULL; \ (x)->next = NULL #else//删除当前节点x#define ngx_queue_remove(x) \ (x)->next->prev = (x)->prev; \ (x)->prev->next = (x)->next#endif#define ngx_queue_split(h, q, n) \ (n)->prev = (h)->prev; \ (n)->prev->next = n; \ (n)->next = q; \ (h)->prev = (q)->prev; \ (h)->prev->next = h; \ (q)->prev = n;//#define ngx_queue_add(h, n) \ (h)->prev->next = (n)->next; \ (n)->next->prev = (h)->prev; \ (h)->prev = (n)->prev; \ (h)->prev->next = h;#define ngx_queue_data(q, type, link) \ (type *) ((u_char *) q - offsetof(type, link))队列的基本操作都在上面了,下面看下两个高级点的操作,队列中间节点的获取或队列的排序。
1,获取队列中间节点: 其实这是一个我们在面试的时候经常被问到的一个题目,当然给出的解决办法也是大家熟知的快慢指针法。需要注意的是:如果队列的节点数为奇数,那么返回中间那个节点,如果为偶数,那么返回后一半的其实节点。
ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue){ ngx_queue_t *middle, *next; middle = ngx_queue_head(queue); //慢指针,获取队列第一个节点 //队列只有一个节点或者为空的时候,直接返回就行了 if (middle == ngx_queue_last(queue)) { return middle; } //快指针也指向第一个节点 next = ngx_queue_head(queue); for ( ;; ) { middle = ngx_queue_next(middle); //慢指针前进一步 next = ngx_queue_next(next); //快指针前进一步 //如果快指针到了最后一个节点了,那么直接返回结果 if (next == ngx_queue_last(queue)) { return middle; } //快指针继续往前走一步 next = ngx_queue_next(next); //如果快指针到了最后一个节点,那么可以直接返回了。 if (next == ngx_queue_last(queue)) { return middle; } }}2,队列排序
voidngx_queue_sort(ngx_queue_t *queue, ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)){ //此函数里的cmp比较函数,需要自己另外提供。 ngx_queue_t *q, *prev, *next; //获取第一个节点,如果只有一个节点,那么直接返回,不用排序了。 q = ngx_queue_head(queue); if (q == ngx_queue_last(queue)) { return; } //从第二个节点开始,和前面的逐个比较 for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) { prev = ngx_queue_prev(q); next = ngx_queue_next(q); ngx_queue_remove(q); //先把需要比较的节点摘出来,然后和前面所有节点进行比较 do { //找到了插入点 if (cmp(prev, q) <= 0) { break; } //继续往前比较 prev = ngx_queue_prev(prev); } while (prev != ngx_queue_sentinel(queue)); //将摘出来的节点插入到最终的位置 ngx_queue_insert_after(prev, q); }}
- Nginx-ngx_queue
- nginx源码学习1 ngx_queue
- Nginx源码完全注释(4)ngx_queue.h / ngx_queue.c
- ngx_queue
- Nginx 中 ngx_queue中的一点理解
- nginx源码学习之ngx_queue:双向链表
- 剖析ngx_queue
- 【nginx】双向队列(ngx_queue.h)的分割队列(链表) ngx_queue_split操作
- 【nginx】双向队列(ngx_queue.h)的合并队列(链表) ngx_queue_add操作
- Nginx源码分析 - 基础数据结构篇 - 双向链表结构 ngx_queue.c
- nginx源码初读(7)--让烦恼从数据结构开始(ngx_queue)
- queue结构分析(二)ngx_queue 未完
- nginx
- Nginx
- Nginx
- Nginx
- Nginx
- nginx
- Linux Shell中各种分号和括号的用法总结
- Node.js-require的使用方法
- hdu 4658 Integer Partition 整数划分+生成函数
- android 缓存Bitmap - 开发文档翻译
- javascript 把字符串转换成json对象
- Nginx-ngx_queue
- Android SDK下载和更新失败的解决方法!!!
- 飘逸的python - 性能调优利器profile及其意义
- jquery, json与ashx的完美结合
- 修改Eclipse启动图标
- 矩阵算法模板
- xml 转xsd->xsd转c,c++
- 判断两个对象是否是同一个对象 | Equals | ReferenceEquals |== | string 类是一个特殊的类
- Marklogic search development -1.Developing Search Applications in MarkLogic Server