数据结构之Linux Kernel双向链表(一)

来源:互联网 发布:淘宝网小狗用品 编辑:程序博客网 时间:2024/05/17 22:24
Linux Kernel双向链表
链表是Linux Kernel中最简单的数据结构。
常规链表 的使用 是将数据结构塞入链表中,Linux Kernel中 链表的使用比较独特 ,是将链表节点塞入数据结构中。通过遍历链表 再通过相对位移 找到数据结构。

Linux Kernel中,链表代码在头文件<linux/list.h>中申明。

struct list_head {   struct list_head *prev;   struct list_head *next;};
next指针指向下一个链表节点,prev指针指向前一个节点。

在使用的时候 嵌入到自己的数据结构中。

struct test_node {    int a;      char b;    struct list_head list;  /* 链表 */};
上例中 test_node中的list.next指向下一个元素,list.prev指向前一个元素。这样 所有的元素 都通过list链表连起来了。

那么如何通过遍历list链表找到真正可以用的数据结构(a和b)呢?

内核中通过container_of()宏实现

#define offsetof(type , member)(   (size_t)(&((type*)0)->member)   )

@type为数据结构 结构体类型。

@member是type结构体中的成员。

offsetof宏是求得成员member相对于type结构体的首地址的偏移量

#define container_of(ptr, type, member)(   (type*)((size_t)ptr - offsetof(type, member))   )

@ptr 是指向大结构体中member成员的指针

@type 是大结构体的类型

@member 是大结构体中的某个成员的名字

container_of宏 是根据大结构体中的某个成员的地址,求得大结构体的首地址

这样Linux Kernel 提供了链表各种最基本的操作方法,而不需要知道list_head所嵌入对象的数据结构。所以不同的数据结构都可以使用Linux 内核链表。

Linux 内核链表常用操作有:

1、初始化链表

static void INIT_LIST_HEAD(struct list_head *list){    list->prev = list;    list->next = list;}
2、插入链表

static void __list_add(struct list_head *list, struct list_head *prev_node, struct list_head *next_node){    list->prev = prev_node;    list->next = next_node;    prev_node->next = list;    next_node->prev = list;}
头插

static void list_add(struct list_head *list, struct list_head *head){    __list_add(list, head, head->next);}
尾插

static void list_add_tail(struct list_head *list , struct list_head *head){    __list_add(list, head->prev, head);}
3、删除节点

static void list_del(struct list_head *list){    list->prev->next = list->next;    list->next->prev = list->prev;    INIT_LIST_HEAD(list);//指向自己}
4、判断是否为空

static int list_is_empty(struct list_head *list){    return list->next == list;}

5、遍历链表

#define list_for_each(cur, head) \for(cur = (head)->next; (cur) != (head); cur = (cur)->next)
安全遍历

#define list_for_each_safe(cur, tmp, head)    for(cur = (head)->next, tmp = (cur)->next; (cur) != (head); cur = (tmp), tmp = (tmp)->next )

6、遍历大结构体

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

参考:Linux内核设计与实现第三版


0 0
原创粉丝点击