nginx之队列

        采用ngx_quque_t来构建双向链表,可以将链表的链接操作相关的数据结构抽象出来,这样有利于进行链表操作函数的编写。其次,用ngx_queue_t结构串接起来的链表可以是不同类型的数据类型(只要这个数据类型包含ngx_quque_t这个数据结构)。打个不恰当的比喻,不管什么样的物品(数据类型),只要物品上有个孔(ngx_quque_t)我们就能用线(ngx_queue_t构成的链)将这些物品串起来。再者,对于链表而言,进行排序,移动元素等操作只需要修改ngx_queue_t中的相关指针即可,所以也称Nginx的双向链表结构为轻量级链表。

源码如下:

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(h)                                                    \
    (h == (h)->prev)
#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
#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
#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_init(q)初始化哨兵结点,令prev字段和next字段均指向其自身;
2. ngx_queue_empty(q)检查哨兵结点的prev字段是否指向其自身,以判断队列是否为空;

3. ngx_queue_insert_head(h, x)在哨兵结点和第一个结点之间插入新结点x;


4. ngx_queue_insert_after(h, x)是ngx_queue_insert_head的别名;

5. ngx_queue_insert_tail(h, x)在最后一个结点和哨兵结点之间插入新结点;


6. ngx_queue_head(h)获取第一个结点;
7. ngx_queue_last(h)获取最后一个结点;
8. ngx_queue_sentinel(h)获取哨兵结点(即参数h);
9. ngx_queue_next(q)获取下一个结点;
10. ngx_queue_prev(q)获取上一个结点;

11. ngx_queue_remove(x)将结点x从队列中移除;


12. ngx_queue_split(h, q, n)将h为哨兵结点的队列中q结点开始到队尾结点的整个链拆分、链接到空的n队列中,h队列中的剩余结点组成新队列;


13. ngx_queue_add(h, n)将n队列中的所有结点按顺序链接到h队列末尾,n队列清空;


14. ngx_queue_middle(queue)使用双倍步进算法寻找queue队列的中间结点;

15. ngx_queue_sort(queue, cmd)使用插入排序算法对queue队列进行排序,完成后在next方向上为升序,prev方向为降序。


16.ngx_queue_data

这里举个列子来说明这个操作的用法。
typedef struct
{
    ngx_int_t num;
    ngx_str_t str;
    ngx_queue_t queue;
}TestNode;

如果我们有一个ngx_queue_t的指针q指向testNode.queue,现在我们不知到testNode的地址,只知道queue,如果我们想访问testNode里

面的成员num,我们必须知道testNode的地址,这样才能访问其num成员。怎样知道testNode的地址呢?这时候ngx_queue_data就闪亮登

场了。我们可以用一下语句来取得testNode的地址:
TestNode* testnode  = ngx_queue_data(q, TestNode, queue);  
这样我们就可以访问num了。




例子:
#include <stdio.h>
#include <stdlib.h>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_conf_file.h>
#include <nginx.h>
#include <ngx_queue.h>

//
//
//这两个东东必须写,不为有编译错误
volatile ngx_cycle_t  *ngx_cycle;

void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
            const char *fmt, ...)
{
}
//
//

typedef struct
{
    ngx_int_t num;
    ngx_str_t str;
    ngx_queue_t queue;
}TestNode;

ngx_int_t compare_node(const ngx_queue_t *left, const ngx_queue_t *right)
{
    TestNode* left_node  = ngx_queue_data(left, TestNode, queue);
    TestNode* right_node = ngx_queue_data(right, TestNode, queue);
    
    return left_node->num > right_node->num;
}


int main()
{
    ngx_queue_t QueHead;
    ngx_queue_init(&QueHead);

    TestNode Node[10];
    ngx_int_t i;
    for (i=0; i<10; ++i)
    {
        Node[i].num = rand()%100;
    }

    ngx_queue_insert_head(&QueHead, &Node[0].queue);
    ngx_queue_insert_tail(&QueHead, &Node[1].queue);
    ngx_queue_insert_after(&QueHead, &Node[2].queue);
    ngx_queue_insert_head(&QueHead, &Node[4].queue);
    ngx_queue_insert_tail(&QueHead, &Node[3].queue);
    ngx_queue_insert_head(&QueHead, &Node[5].queue);
    ngx_queue_insert_tail(&QueHead, &Node[6].queue);
    ngx_queue_insert_after(&QueHead, &Node[7].queue);
    ngx_queue_insert_head(&QueHead, &Node[8].queue);
    ngx_queue_insert_tail(&QueHead, &Node[9].queue);

    ngx_queue_t *q;
    for (q = ngx_queue_head(&QueHead); q != ngx_queue_sentinel(&QueHead); q = ngx_queue_next(q))
    {
        TestNode* Node = ngx_queue_data(q, TestNode, queue);
        printf("Num=%d\n", Node->num);
    }

    ngx_queue_sort(&QueHead, compare_node);
    
    printf("\n");
    for (q = ngx_queue_head(&QueHead); q != ngx_queue_sentinel(&QueHead); q = ngx_queue_next(q))
    {
        TestNode* Node = ngx_queue_data(q, TestNode, queue);
        printf("Num=%d\n", Node->num);
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值