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

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值