libevent裏面的尾隊列TAILQ
一、TAILQ的隊列頭
TAILQ把整個隊列頭單獨抽象爲一個結構體TAILQ_HEAD,如下:
#ifndef TAILQ_HEAD
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element*/ \
struct type **tqh_last; /* address of last next element*/ \
}
#endif
tqh_first是一個一級指針,指向隊列的第一個元素;tqh_last是一個二級指針,它指向最後一個元素中的tqe_next的地址。
上面的定義中不需要在最後的}後添加分行(;)
TAILQ_HEAD(queue_head_s, queue_entry_s) queue_head_t;
宏展開後就成了:
struct queue_head_s {
struct queue_entry_s *tqh_first;
struct queue_entry_s **tqh_last;
} queue_head_t;
初始化隊列頭:
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAIL_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
head->last = &TAILQ_FIRST((head)); \
} while(0)
二、TAILQ的隊列元素
#ifndef TAILQ_ENTRY
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /*next element*/ \
struct type **tqe_prev; /*address of previous next element*/ \
}
#endif
和前面的TAILQ_HEAD相比,TAILQ_ENTRY參數裏面沒有了name,即沒有結構體名,所以該結構體只能作爲一個匿名結構體,所以它一般都是另外一個結構體或者聯合體的成員。如:
struct queue_entry_s {
int element;
TAILQ_ENTRY(queue_entry_s) entry;
};
展開後就變成
struct queue_entry_s {
int element;
struct { struct queue_entry_s *tqe_next; struct queue_entry_s *tqe_prev; } entry;
};
三、插入隊列元素
考慮到隊列是先進先出,這裏研究從尾部插入新節點, 從頭部刪除節點。
1. 尾部插入
head: 隊列頭結點
elm: 實際節點對象
field: 隊列節點元素
#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)
TAILQ_INSERT_TAIL(head, queue_entry, entry);
展開後變成:
do {
(queue_entry)->entry.tqe_next = NULL;
(queue_entry)->entry.tqe_prev = (head)->tqh_last;
*(head)->tqh_last = (queue_entry);
(head)->tqh_last =& ((queue_entry)->entry.tqe_next);
} while(0);
1) (head)->tqh_last 指向最後一個節點的next指針,所以在隊列最後添加一個節點的時候,
*(head)->tqh_last = elem
2) (head)->tqh_last 指向最後一個節點的next指針
(head)->tqh_last =& ((queue_entry)->entry.tqe_next);
初始化狀態,一個已經初始化的隊列頭,和一個待插入的隊列元素
對新插入的元素的指針進行賦值,tqe_prev指向前一個next指針的地址,在尾部插入的情況下,就是tqh_last,因爲tqh_last指向最後一個next指針的地址
將tqe_prev賦值爲tqh_last,則tqe_prev和tqh_last所指的都是tqh_first.
2.更新tqh_first
添加第一個元素的時候,tqh_last就是tqh_first,所以更新tqh_first可以統一爲更新(tqh_last)
3.更新tqh_last
4.調整一下變成
再次插入新的一個元素
step 0
step 1
step 2
四、刪除隊列元素
#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)->filed.tqe_prev = (elm)->filed.tqe_next; \
} while(0)
隊列的一個特點就是先進先出,那麼考慮刪除第一個節點元素
已知如下隊列,從中刪除元素1的節點
step1
step2
step 3
最後還應該調用另外的釋放函數來釋放elm節點
五、隊列中的第一個元素
#define TAILQ_FIRST(head) ((head)->tqh_first)
六、當前元素的下一個元素
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
七、列表隊列中的每一個元素
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST(head); \
(var) != NULL; \
(var) = TAILQ_NEXT(var, field))
八、實例
gwwu@hz-dev2.aerohive.com:~/test/tailq>more queue.h
#ifndef __QUEUE_H__
#define __QUEUE_H__
#ifndef TAILQ_HEAD
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element*/ \
struct type **tqh_last; /* address of last next element*/ \
}
#endif
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &((head)->tqh_first); \
} while(0)
#ifndef TAILQ_ENTRY
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; \
struct type **tqe_prev; \
}
#endif
#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)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != NULL; \
(var) = TAILQ_NEXT(var, field))
#endif
[email protected]:~/test/tailq>more int_queue.c
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
struct queue_entry_t {
int value;
TAILQ_ENTRY(queue_entry_t) entry;
};
TAILQ_HEAD(queue_head_t, queue_entry_t); //define queue_head_t structure
int main(int argc, char *argv[])
{
struct queue_head_t queue_head;
struct queue_entry_t *p;
int i;
TAILQ_INIT(&queue_head);
for (i = 0; i < 3; i++) {
p = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
if (p == NULL) {
printf("malloc queue entry(%d) failed\n", i);
return -1;
}
p->value = i;
TAILQ_INSERT_TAIL(&queue_head, p, entry);
}
TAILQ_FOREACH(p, &queue_head, entry) {
printf("the %d node\n", p->value);
}
TAILQ_FOREACH(p, &queue_head, entry) {
TAILQ_REMOVE(&queue_head, p, entry);
}
return 0;
}
編譯運行:
gwwu@hz-dev2.aerohive.com:~/test/tailq>gcc -g int_queue.c -o int_queue -Wall
gwwu@hz-dev2.aerohive.com:~/test/tailq>./int_queue
the 0 node
the 1 node
the 2 node