學習 linux 鏈表使用方法

最近看了幾個 RTOS 內核文件,發現內核用到的鏈表都使用宏來操做。

看內容應該是借鑑了 linuxlist.h 代碼。 好奇研究 linux 的鏈表代碼,學習記錄下。

下面是我常用的鏈表結構定義方式:

typedef struct _dlink_node {
    void *pData;                    // 存放用戶數據對象指針
    struct _dlink_node *ptPre;
    struct _dlink_node *ptNext;
} dlink_node_t;

typedef struct _dlink_list {
    dlink_node_t *ptHead;
    int32_t nCount;
} dlink_list_t;

使用方式一般是先定義一個鏈表控制塊對象 dlink_list_t list , 所有的節點增刪改查都是針對這個鏈表對象進行操作。

比如插入一個數據的僞代碼如下:

dlink_node_t node = {.pData = &UserData};

dlink_list_insert(&list, 1, &node);

然而,linux 的鏈表實現方式與此不同,沒有定義的鏈表管理控制塊 list。而是把 dlink_node_t 這樣的節點直接定義到目標對象中。

通過 dlink_node_t 中的 prenext 指針直接建立對象之間的聯繫。

注:可以直接在 linxu 主機中查看源碼文件,我是用的騰訊的虛擬雲主機

[root@lzlinks ~]# vim /usr/src/kernels/3.10.0-957.5.1.el7.x86_64/include/linux/types.h
[root@lzlinks ~]# vim /usr/src/kernels/3.10.0-957.5.1.el7.x86_64/include/linux/list.h

linux 中,鏈表結構體定義在 types.h 文件中, 定義如下:

struct list_head {
	struct list_head *next, *prev;
};

可以看到,Linux 內核中定義的是一個僅僅只有兩個指針,沒有用戶數據的雙向循環鏈表結構體。

用戶需要把 list 結構體內嵌到自己的數據對象中,通過 list.h 提供的鏈表操作宏,完成鏈表的初始化和增刪改查操作。

struct user_object {
    struct list_head    list_node;
    int                 data;
}

/**
    \breief: usr object list

                  object               object
  ...+++ ->next  +++++++++  -> next  +++++++++  -> next +++...
       +         +  list +           +  list +          +
  ...+++ <- pre  +++++++++  <- pre   +++++++++  <- pre  +++...
       +         +  data +           +  data +          +
  ...+++         +++++++++           +++++++++          +++...

*/

linux 鏈表的常用API:

void list_add(struct list_head *new, struct list_head *head);
void list_add_tail(struct list_head *new, struct list_head *head);

// 各種宏定義,都是直接操作鏈表節點
#define list_for_each(pos, head) \
           for (pos = (head)->next; pos != (head); pos = pos->next)

#define list_for_each_entry(pos, head, member)                          \
           for (pos = list_entry((head)->next, typeof(*pos), member);   \
                &pos->member != (head);    \
                pos = list_entry(pos->member.next, typeof(*pos), member))

這樣做的好處是:

* 鏈表可以出現在任何位置 

* 可以給鏈表任意命名  

* 一個結構體可以屬於多個鏈表,這是 Linux 內核的特性要求數據結構必須做到的

缺點是:

* 統計鏈表中節點的數量,需要遍歷。當然也可以定義一個變量,作爲計數器。

* 用戶操作不當可能會破壞鏈表結構
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章