转载请注明出处: http://blog.csdn.net/luotuo44/article/details/38374009
Libevent源码中有一个queue.h文件,位于compat/sys目录下。该文件里面定义了5个数据结构,其中TAILQ_QUEUE是使得最广泛的。本文就说一下这个数据结构。
队列结构体:
TAILQ_QUEUE由下面两个结构体一起配合工作。
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
//和前面的TAILQ_HEAD不同,这里的结构体并没有name.即没有结构体名。
//所以该结构体只能作为一个匿名结构体。所以,它一般都是另外一个结构体
//或者共用体的成员
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
由这两个结构体配合构造出来的队列一般如下图所示:
图中,一级指针指向的是queue_entry_t这个结构体,即存储queue_entry_t这个结构体的地址值。二级指针存储的是一级地址变量的地址值。所以二级指针指向的是图中的一级指针,而非结构体。图中的1,2, 3为队列元素保存的一些值。
队列操作宏函数以及使用例子:
除了这两个结构体,在queue.h文件中,还为TAILQ_QUEUE定义了一系列的访问和操作函数。很不幸,它们是一些宏定义。这里就简单贴几个函数(准确来说,不是函数)的代码。#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
} while (0)
这些宏是很难看的,也没必要直接去看这些宏。下面来看一个使用例子。有例子更容易理解。
//队列中的元素结构体。它有一个值,并且有前向指针和后向指针
//通过前后像指针,把队列中的节点(元素)连接起来
struct queue_entry_t
{
int value;
//从TAILQ_ENTRY的定义可知,它只能是结构体或者共用体的成员变量
TAILQ_ENTRY(queue_entry_t)entry;
};
//定义一个结构体,结构体名为queue_head_t,成员变量类型为queue_entry_t
//就像有头节点的链表那样,这个是队列头。它有两个指针,分别指向队列的头和尾
TAILQ_HEAD(queue_head_t, queue_entry_t);
int main(int argc, char **argv)
{
struct queue_head_t queue_head;
st