libevent 学习----------尾队列 tail queue

来源:互联网 发布:公众号运营知乎 编辑:程序博客网 时间:2024/06/12 20:02

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);

  1. 初始化状态,一个已经初始化的队列头,和一个待插入的队列元素
    这里写图片描述

  2. 对新插入的元素的指针进行赋值,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.调整一下变成

这里写图片描述

  1. 再次插入新的一个元素
    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
gwwu@hz-dev2.aerohive.com:~/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 structureint 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 -Wallgwwu@hz-dev2.aerohive.com:~/test/tailq>./int_queue the 0 nodethe 1 nodethe 2 node
原创粉丝点击