Nginx源碼初探之數據結構 - 隊列數據結構

隊列介紹

       隊列是有序集合,先進先出FIFO,隊列的概念很好理解,隊列的應用也非常廣泛如:循環隊列、阻塞隊列、併發隊列、優先級隊列等。Nginx數據結構是循環隊列,prev前置節點環和next後置節點環。

       Nginx鏈表還是非常有特色的,它是一種輕量級鏈表,這種鏈表不包含數據內容,只包含前後節點指針。在使用的時候需要作爲帶有節點變量的結構體(宿主)的成員變量存在(寄宿鏈表)。這個結構並非Nginx獨有,比如Linux操作系統的鏈表

1.數據結構

typedef struct ngx_queue_s  ngx_queue_t;

struct ngx_queue_s {
    ngx_queue_t  *prev;
    ngx_queue_t  *next;
};

2.操作

        ngx_queue_t是輕量級鏈表操作非常好理解,就是維護節點關係,保證雙鏈表結構。這些和關於雙鏈表的基本操作是相同的,Nginx代碼很清晰可自行查看。

2.1獲取節點內容
根據寄宿鏈表獲取節點內容的原理來獲取ngx_queue_t的內容:
1.宿主結構體本身看做一個連續的內存區域
2.利用offsetof宏計算出寄宿鏈表成員變量相對於結構體起始位置的偏移量
3.寄宿鏈表的起始地址-寄宿鏈表成員變量相對於結構體起始位置的偏移量=結構體的起始位置

#define ngx_queue_data(q, type, link)                                         \
    (type *) ((u_char *) q - offsetof(type, link))

2.2獲取中間節點
這是個很機巧的問題,雙路遍歷,移動速度相差一倍,速度快的指針到達末尾時,速度慢的就在中間位置。

ngx_queue_t *
ngx_queue_middle(ngx_queue_t *queue)
{
    ngx_queue_t  *middle, *next;
     /*1.首尾相等,只有一個節點直接返回*/
    middle = ngx_queue_head(queue);

    if (middle == ngx_queue_last(queue)) {
        return middle;
    }

    next = ngx_queue_head(queue);
    /*2.雙路遍歷,middle遍歷用於獲取中間節點,next遍歷用於尋找last節點。由於next遍歷是middle遍歷的2倍,所以當next遍歷到last節點時,middle遍歷到中間節點*/
    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;
        }
    }
}

     Nginx的隊列吸取了Linux系統的很多特點,具有輕量級,速度快的特點。

 

 

發佈了27 篇原創文章 · 獲贊 1 · 訪問量 2236
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章