內核雙鏈表:
3.1這裏的雙鏈表程序是很簡單,也是使用了許多宏和內聯函數,我們現在主要來看下程序。內核中雙鏈表的結構體定義如下:
structlist_head {
struct list_head *next, *prev;
}; 這裏的頭部只有兩個指針域,相當奇怪,我們平時定義的鏈表主要都是節點域與指針域。這裏這麼用,自然有好處,將指針直接與數據剝離,對於內核中擁有不同數據域的鏈表即可公用一套指針域。現在這是我能想到的。不然前面的container_of宏也沒有多大意義了。
3.2程序接下來進行數據的初始化
#defineLIST_HEAD_INIT(name) { &(name), &(name) }
#defineLIST_HEAD(name) \
struct list_head name =LIST_HEAD_INIT(name)
#defineINIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev= (ptr); \
} while(0)
這裏主要是初始化頭結點,假如有一個使用中的結構體,這裏的代碼即可進行宏替換。
第二個宏就類似於,structlist_head _head; _head={&(_head),&(head)}; 第三個即是將next和prev指針都指向本身。接下來看看頭插法和尾插法的實現。
static inline void __list_add(structlist_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/*尾插法實現*/
static inline void list_add(struct list_head *new, structlist_head *head)
{
__list_add(new, head, head->next);
}
/*頭插法實現*/
static inline void list_add_tail(struct list_head *new,struct list_head *head)
{
__list_add(new, head->prev, head);
}
其實也是比較簡單,不過這裏封裝的很好。
3.3 接下來看看從鏈表中刪除一個節點。
staticinline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
staticinline void list_del(struct list_head *entry)
{
__list_del(entry->prev,entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
由於這裏是沒有進行內存釋放的,所以用戶在自己使用時,一定要進行手動釋放內存[自己定義的結構體],否則會出現野指針和內存泄露。
3.4 進行移動
/*移動到某節點頭部*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev,list->next);
list_add(list, head);
}
/*移動到某節點尾部*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev,list->next);
list_add_tail(list, head);
}
這兩個思想都是一樣,先刪除,在插入。
3.5 進行鏈表的遍歷
#definelist_for_each(pos, head) \
for (pos = (head)->next,prefetch(pos->next); pos != (head); \
pos= pos->next, prefetch(pos->next))
其實也就是一個for循環,使用宏進行了重定義。
pos作爲中間變量,依次遞加,其中prefetch主要保證了地址的有效,還有這裏面涉及到流的欲抓取,據說能夠使用這個函數通常可以減少緩存缺失和停頓,沒試驗過,^_^||,前面的功能有點像assert。
這裏還實現了雙向鏈表的前置掃描,這裏不再贅述。
我們這裏還有一個安全的鏈表遍歷。這裏何爲安全,看下面代碼。
#define list_for_each_safe(pos, n, head) \
for(pos = (head)->next, n = pos->next; pos != (head); \
pos= n, n = pos->next)
舉個例子就行,在list_for_each遍歷的時候,你敢刪除一個節點嗎?
3.6接下來這個宏比較吊
#define list_for_each_entry(pos, head,member) \
for(pos = list_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = list_entry(pos->member.next,typeof(*pos), member), \
prefetch(pos->member.next))
仍然是遍歷的過程。
pos = list_entry((head)->next,typeof(*pos), member), \
prefetch(pos->member.next);
首先是獲取member成員所在節點pos的首地址。就是container_of宏的作用,然後prefetch告訴cpu接下來會獲取下一個節點,達到預取的目的。
&pos->member != (head); 這個是用於循環條件判斷。
pos = list_entry(pos->member.next,typeof(*pos), member), \
prefetch(pos->member.next))
這個類似於第一個。
接下來我們使用這些個函數,實現簡答的一些程序設計。[不可直接套用list.h]文件,這裏很多函數都是內核態的,非用戶態。 我們來刪繁就簡下。
double_list.h
#ifndef _double_list_
#define _double_list_
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/*用戶結構體*/
typedef struct _TApple
{
intweight;
charcolor[10];
charname[20];
}TApple;
struct list_head {
TApple*pApple;
structlist_head *next, *prev;
};
//#define LIST_HEAD_INIT(name) { &(name),&(name) }
//#define LIST_HEAD(name) \
structlist_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next= (ptr); (ptr)->prev = (ptr); \
} while (0)
#define container(ptr, type, member) ({ \
const typeof(((type*)0)->member)* __mptr =(ptr); \
(type*)((char*)__mptr - offsetof(type, member)); })
static inline void __list_add(structlist_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev= new;
new->next= next;
new->prev= prev;
prev->next= new;
}
static inline void list_add(struct list_head*new, struct list_head *head)
{
__list_add(new,head, head->next);
}
static inline void list_add_tail(structlist_head *new, struct list_head *head)
{
__list_add(new,head->prev, head);
}
static inline void __list_del(structlist_head * prev, struct list_head * next)
{
next->prev= prev;
prev->next= next;
}
static inline void list_del(struct list_head*entry)
{
__list_del(entry->prev,entry->next);
entry->next= LIST_POISON1;
entry->prev= LIST_POISON2;
}
#define list_for_each(pos, head) \
for(pos = (head)->next, pos->next!=NULL; pos != (head); \
pos= pos->next)
#define list_for_each_safe(pos, n, head) \
for(pos = (head)->next, n = pos->next; pos != (head); \
pos= n, n = pos->next)
#define list_for_each_entry_safe(pos, n,head, member) \
for(pos = container((head)->next, typeof(*pos), member), \
n= container(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = container(n->member.next,typeof(*n), member))
#endif
double_list.c
#include "double_list.h"
int main()
{
TApple*pApple = (TApple*)malloc(sizeof(TApple));
memset(pApple,0x00, sizeof(TApple));
pApple->weight= 10;
strcpy(pApple->color,"紅色");
strcpy(pApple->name,"紅色富士山");
structlist_head* head_node = (struct list_head*)malloc(sizeof(struct list_head));
INIT_LIST_HEAD(head_node);
head_node->pApple= pApple;
printf("pApple=%p,head_node=%p \n", pApple,head_node);
/*untilnow, you can see a head node*/
/************************************************************************/
TApple*pApple1 = (TApple*)malloc(sizeof(TApple));
memset(pApple1,0x00, sizeof(TApple));
pApple1->weight= 10;
strcpy(pApple1->color,"綠色");
strcpy(pApple1->name,"綠色富士山");
structlist_head* head_node1 = (struct list_head*)malloc(sizeof(struct list_head));
head_node1->pApple= pApple1;
list_add(head_node1,head_node);
printf("pApple1=%p,head_node1=%p \n", pApple1,head_node1);
/************************************************************************/
TApple*pApple2 = (TApple*)malloc(sizeof(TApple));
memset(pApple2,0x00, sizeof(TApple));
pApple2->weight= 10;
strcpy(pApple2->color,"黃色");
strcpy(pApple2->name,"黃色富士山");
structlist_head* head_node2 = (struct list_head*)malloc(sizeof(struct list_head));
head_node2->pApple= pApple2;
list_add(head_node2,head_node);
printf("pApple2=%p,head_node2=%p \n", pApple2,head_node2);
/***********************************************************************/
structlist_head* step_pointer = NULL;
structlist_head* temp_pointer = NULL;
intidx = 0;
list_for_each_safe(step_pointer,temp_pointer,head_node)
{
printf("weight=[%d],color=[%s], name=[%s]\n",step_pointer->pApple->weight,step_pointer->pApple->color,step_pointer->pApple->name);
printf("index=%d,step_pointer->pApple=%p, step_pointer=%p \n", idx,step_pointer->pApple,step_pointer);
free(step_pointer->pApple);
step_pointer->pApple=NULL;
free(step_pointer);
step_pointer= NULL;
idx++;
}
/*******************delhead**********************/
printf("weight=[%d],color=[%s], name=[%s]\n",head_node->pApple->weight,head_node->pApple->color,head_node->pApple->name);
printf("index=%d,head_node->pApple=%p, head_node=%p \n", idx,head_node->pApple,head_node);
free(head_node->pApple);
head_node->pApple=NULL;
free(head_node);
head_node= NULL;
return0;
}