nginx队列模块的分析和使用

nginx队列模块的设计挺精妙的,也算是用一个C语言实现泛型的典型例子了,我将其独立出来,写上注释和测试例子,方便以后查看。

#ifndef _NGX_QUEUE_H_INCLUDED_
#define _NGX_QUEUE_H_INCLUDED_

#include <stdio.h>
#include <stddef.h>

typedef struct ngx_queue_s  ngx_queue_t;

//队列的节点,也直接表示队列,
//但它不直接保存数据,只保存了前后两个结点的指针
//由下面操作函数可以看出,它是一个带头结点的双向循环队列
struct ngx_queue_s {
	ngx_queue_t  *prev;
	ngx_queue_t  *next;
};

//初始化队列q所指向的指针,两个指针都指向它自己,
//在这里,q是队列的头结点,起表头的作用,不储存信息
#define ngx_queue_init(q)                                                     \
	(q)->prev = q;                                                            \
	(q)->next = q

//如果表头的下个结点是它自己,那么这就是一个空队列
#define ngx_queue_empty(h)                                                    \
	(h == (h)->prev)

//向h结点的后面插入一个结点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

//向h结点的前面插入一个结点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;

//将以n为表头的队列接到以h为表头的队列后面
#define ngx_queue_add(h, n)                                                   \
	(h)->prev->next = (n)->next;                                              \
	(n)->next->prev = (h)->prev;                                              \
	(h)->prev = (n)->prev;                                                    \
	(h)->prev->next = h;

//寻找包含line(ngx_queue_t)成员的结构体,返回这个结构体的指针
#define ngx_queue_data(q, type, link)                                         \
	(type *) ((char *) q - offsetof(type, link))


ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
void ngx_queue_sort(ngx_queue_t *queue,
					int (*cmp)(const ngx_queue_t *, const ngx_queue_t *));


#endif /* _NGX_QUEUE_H_INCLUDED_ */




//寻找队列的中点
//从表头开始,middle指针每次前进一个结点,next指针每次前进两个结点
//那么,next指针到达表尾时,middle
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;
		}
	}
}

//用稳定插入法排序该队列
void
ngx_queue_sort(ngx_queue_t *queue,
			   int (*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);
	}
}

//

//使用例子

//若想使用ngx_queue_t的功能,只需在自己的结构体中包含一个ngx_queue_t成员就可以了
//(当然,初始化的时候要小心)
typedef struct
{
	int num;
	char str[1024];
	ngx_queue_t queue;
}TestNode;

//TestNode比较函数
int CompTestNode(const ngx_queue_t *a, const ngx_queue_t *b)
{
	TestNode *anode = ngx_queue_data(a, TestNode, queue);
	TestNode *bnode = ngx_queue_data(b, TestNode, queue);
	return anode->num > bnode->num;
}

//输出整个TestNode队列
void PrintNodeQueue(const ngx_queue_t *que)
{
	ngx_queue_t *q;
	//遍历整个队列
	for( q = ngx_queue_head(que);
		q != ngx_queue_sentinel(que);
		q = ngx_queue_next(q) )
	{
		TestNode *node = ngx_queue_data(q, TestNode, queue);
		printf("%d  %s\n", node->num, node->str);
	}
}



int main()
{
	TestNode node[10];
	int i;

	ngx_queue_t content;
	ngx_queue_init(&content);
	for(i=0; i<10; i++)
	{
		node[i].num = i;
		sprintf(node[i].str, "%d--%d--%d", i, i, i);
		ngx_queue_insert_head(&content, &node[i].queue);
	}
	PrintNodeQueue(&content);
	
	ngx_queue_sort(&content, CompTestNode);
	printf("\nAfter sort:\n");
	PrintNodeQueue(&content);

	
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值