libevent 學習----------尾隊列 tail queue

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
[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
發佈了90 篇原創文章 · 獲贊 24 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章