1.概述
nginx为了跨平台底层封装了自己的数据结构,今天学了ngx_queue_t这个数据结构,这个结构实现了双向队列,该双向队列可以应用到任意结构体中把相应的结构体按照队列的方式组织起来.
2.代码
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#ifndef _NGX_QUEUE_H_INCLUDED_
#define _NGX_QUEUE_H_INCLUDED_
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))
ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
void ngx_queue_sort(ngx_queue_t *queue,
ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
#endif /* _NGX_QUEUE_H_INCLUDED_ */
ngx_queue_data宏才是这个数据结构能够用到任何地方的关键,该宏通过指向ngx_queue_t的指针来算出自己的节点的指针.从而提供访问节点中其他数据的能力.
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;
}
}
}
/* the stable insertion sort */
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 一个小的case来使用上面定义的数据结构
#include "ngxqueue.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct MyNode{
int x;
double y;
ngx_queue_t ngx_queue;
} MyNode;
struct eventQueue{
int count;
int other;
ngx_queue_t queue_sentinel;
};
struct eventQueue evqueue;
static int
eventQueueInit(struct eventQueue *evqueue){
evqueue->count = 0;
evqueue->other = 0;
ngx_queue_init(&evqueue->queue_sentinel);
return 0;
}
static int
eventQueueAdd(struct eventQueue* evqueue,struct MyNode* node){
ngx_queue_insert_tail(&evqueue->queue_sentinel,&node->ngx_queue);
evqueue->count++;
}
static void
printtheQ(struct eventQueue* evqueue){
ngx_queue_t *p =ngx_queue_head(&evqueue->queue_sentinel);
while( p != &evqueue->queue_sentinel){
struct MyNode* tmp = ngx_queue_data(p,struct MyNode,ngx_queue);
printf("the value is %d\n",tmp->x);
p = ngx_queue_next(p);
}
}
#define QNUM 5
int main(){
eventQueueInit(&evqueue);
int i;
for(i =0 ; i < QNUM ;i++){
struct MyNode* p = (struct MyNode*) malloc(sizeof(struct MyNode));
p->x = i;
p->y = i;
eventQueueAdd(&evqueue,p);
}
printtheQ(&evqueue);
}
节点MyNode 将ngx_queue_t作为成员提供连接的能力, ngx_queue_t的哨兵节点作为eventQueue的成员, eventQueue可以负责管理整个队列,比如说count 负责记录整个队列的元素个数, 就可以基于ngx_queue_t 提供的操作来封装eventQueue自己的接口了.
比如在printQueue函数中调用ngx_queue_data来读取队列中节点的信息.
4总结
在c语言中如此实现的数据结构提供了模板的能力, 数据结构不依赖于特定的类.