nginx----queue

来源:互联网 发布:dsa p57 数据升级工具 编辑:程序博客网 时间:2024/06/04 22:16

1、数据结构

nginx中queue的数据结构非常简单,其中并不包含任何实际数据相关的结构,只有两个指针用于找到前后的元素。

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

2、基本操作

queue的操作也几乎都是通过宏定义来实现的,队列包含的具体操作如下:

#define ngx_queue_init(q)          //队列的初始化                       #define ngx_queue_empty(h)         //判断队列是否为空#define ngx_queue_insert_head(h, x)        //在头节点后插入一个节点      #define ngx_queue_insert_tail(h, x)        //在尾部节点后插入一个节点                  #define ngx_queue_head(h)                 //返回队列的头节点         #define ngx_queue_last(h)                 //返回队列的尾部节点                  #define ngx_queue_next(q)                 //返回q节点后面的一个节点                       #define ngx_queue_prev(q)                 //返回q节点的前一个节点#define ngx_queue_remove(x)               //将节点x从队列中移除#define ngx_queue_split(h, q, n)          //分割队列           #define ngx_queue_add(h, n)               //链接队列                             
队列的这些操作与以前学过的链表的操作十分类似。除了上述操作外,链表还通过函数实现了获取中间节点以及队列排序。

获取中间节点:

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;        }    }}
有上述代码可知,middle和next初始时都是指向队列的头节点,而middle每次移动一个节点,next每次移动两个节点,则当next遍历完整个队列时,middle则刚好遍历到了队列的一半,即指向队列的中间节点。

eg:middle=2时,next=2或3;middle=3时,next=4或5;即当next指向最后一个节点时,middle总是指向中间节点,即第(totalNodeNum/2 + 1)个节点。当节点总数为奇数时,则恰好返回中间节点,当节点总数为偶数时,则返回后半部分的第一个节点。

上图分别对应了偶数个节点和奇数个节点的情况

队列排序:

voidngx_queue_sort(ngx_queue_t *queue,    ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *)){    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);  //将节点插入到该位置中    }}
队列排序是依次遍历队列中的每一个节点,将其插入到前面已经排好序的队列中,这是一种稳定的简单插入排序。

3、由于单纯的队列只是简单的构成队列,而不涉及数据部分的,因此当我们使用队列时,需要自己设计数据结构,在其中嵌入数据部分和队列。

一个简单的示意图如下:


队列在数据结构中间,上面或下面都可能存放其它数据。通过queue将所有节点链接起来。

可通过如下的宏定义获取队列节点数据

#define ngx_queue_data(q, type, link)                                         \    (type *) ((u_char *) q - offsetof(type, link))
其中q为指向queue的指针,type为自定义的嵌入了数据和队列的结构,link为queue结构在type结构中的名称

q减去queue在结构体中的偏移量即可得到指向type结构首地址的指针,然后通过(type *)类型转换即可得到type结构。如下图所示:


0 0
原创粉丝点击