理解linux內核中的rbtree

red-blacktree(RB樹)是一種平衡二叉樹,它主要用於存儲或者說索引可排序的鍵
 
  值對數據。RB樹(紅黑樹)與radix樹和hash表都不同。radix樹是一種比較適合用於
   存儲稀疏的數據集而且將用一個大整數進行插入,刪除,查找的操作基礎。而hash表
   並不是以某種排序順序進行存儲,而且必須指定大小和hash函數。
    
   RB樹與AVL樹很相似,但是比AVL樹有更好的插入和刪除最壞情況的時間複雜度,以及
    O(logn)的最壞查找時間複雜度。
    
    引用:
   在Linux中有很多地方用到了RD樹。anticipatory, deadline, 和CFQ I/O調度都使用
   的是RB樹進行請求跟蹤,還有CD/DVD驅動的包管理也是如此。
   高精度計時器(high-resolution timer)使用RB樹組織定時請求。
   EXT3文件系統也使用RB樹來管理目錄。
   虛擬存儲管理系統也是有RB樹進行VMAs(Virtual Memory Areas)的管理。
   當然還有文件描述符,密碼鑰匙,“等級令牌桶”調度的網絡數據包都是用RB數據進
   行組織和管理的。
    
    相關資料:
    Linux WeeklyNews article on red-black trees
   http://lwn.net/Articles/184495/
    Wikipediaentry on red-black trees
   http://en.wikipedia.org/wiki/Red-black_tree
    
   可見RB樹(紅黑樹)在Linux內核中的重要性。
    
Linux內核的RB樹實現
---------------------------------------
   在Linux內核源代碼中rb樹的實現在lib/rbtree.c文件中,可以通過
    #include"linux/rbtree.h"進行使用。
    
   在Linux內核中的RB樹實現與傳統的實現方式有些不同。它對針對內核對速度的需要做
   了些優化。每一個rb_node節點是嵌入在用RB樹進行組織的數據結構中,而不是用
   rb_node指針進行數據結構的組織。
    
創建一棵RB樹
---------------------
   在RB樹裏的數據節點包含了一個rb_node數據結構節點。如下:
    structmytype {
       struct rb_node node;
       char *keystring;
    };
    
   可以通過container_of宏取得包含了rb_node的數據結構。也可以通過
   rb_entry(node,type,member)取得。
    其實是#definerb_entry(node,type,member) container_of(node,type,member)
    
   這裏順便說一下如何通過container_of取得包含rb_node的數據結構指針:
   在Linux內核代碼裏有這樣的宏定義:
    #definecontainer_of(ptr, type, member) ({\
    consttypeof( ((type *)0)->member ) *__mptr =(ptr);\
    (type *)((char *)__mptr - offsetof(type,member) );})
    
    #defineoffsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
    
    那麼對於structmytype,如何通過其成員node來取得走首地址呢:
   我們肯定已經知道node的地址,假設爲pnode;
    structmytype* x = rb_entry(pnode, struct mytype, node);
   意思是,取得pnode所被包含的數據結構對象的首地址,pnode是指向struct mytype的
   成員node的指針。
   宏替換完後就是這個樣子:
    ({
       const typeof( ((struct mytype *)0)->node ) *__mptr =(pnode);
       (struct mytype *)((char *)__mptr-((size_t)&((structmytype*)0)->node));
    })
    
   typeof取得struct mytype中node成員的類型,用這個類型定義一個新的指針,把
   pnode的值賦給它,在這裏起到了類型檢查的作用。
   offsetof(type,member)是取得member在type對象中相對於此對象首地址的偏移量。
   那麼用__mptr減去這個偏移量就得到了type對象的起始地址。也就得到了把rb_node
   作爲嵌入的管理數據結構的對象起始地址。
    
    x = y -offset
    ----------<--x
   |       |
   |       |
    |--------|<--offset  <--y
   |      
發佈了32 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章