nginx----queue

本文介绍了nginx中queue数据结构的简单设计,包括如何获取中间节点以及如何进行队列排序。队列仅包含前后指针,不存储实际数据,使用时需结合自定义数据结构。示例展示了如何在数据结构中嵌入队列,并通过宏定义获取队列节点的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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)个节点。当节点总数为奇数时,则恰好返回中间节点,当节点总数为偶数时,则返回后半部分的第一个节点。

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

队列排序:

void
ngx_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结构。如下图所示:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值