还在写传统链表?简析Linux内核中的侵入式链表

906 阅读2分钟

本文首先给出了传统链表,即在课本上学过的链表和侵入式链表的实现,而后将两者进行了对比,阐明了侵入式链表的优势,并给出了对应的实现代码与详细的注释。

一句话总结

传统链表是在链表节点中包含数据,而侵入式链表是在数据内部包含链表节点

传统链表

概念: 正如从数据结构课本中学到的那样,传统链表由节点构成,每个节点包含数据和指向序列中下一个节点的指针,以及一个指向前一个节点的指针。其C语言实现如下所示:

struct node {
    void *data;
    struct node *next;
    struct node *pre;
};

引用知乎上的一张图片image.png

侵入式链表

侵入式链表(Intrusive List)是一种在数据结构内部直接包含链表节点的方法。这与传统链表不同,传统链表通常有一个单独的节点结构,用来存储数据和指向列表中下一个节点的指针。侵入式链表直接在要组成链表的数据结构中嵌入链表节点。

image.png

其对应的C语言实现如下所示:

这是Linux内核中定义的典型侵入式链表节点的示例:

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

然后你的数据结构会嵌入这个list_head

struct my_data {
    data_type data;
    struct list_head list;
};

优势

在说侵入式链表的优势前,先说传统链表的缺陷:

  • 一个数据对象只能属于一个链表节点:如果你想在两个节点之间共享一个对象,就需要使用指针或者用deepcopy。
  • 每个链表节点中,data元素的类型是指定的,也就是一个链表中,每个节点存储的数据类型必须是相同的。
  • 不同的链表,在构建api的时候必须要构建多套函数。
  • 难以处理每个节点数据个数不同的情况

由此,侵入式链表的优势为:

  • 操作侵入式链表根本不调用任何内存管理。与动态内存相关的时间和大小开销可以最小化。
  • 同一个数据对象可以同时插入到多个链表中,对象大小的开销很小。同样,一个链表可以用于多种对象。
  • 与语义上等价的指针容器相比,遍历侵入式容器需要更少的内存访问——迭代更快。

以上就是关于linux内核中使用的侵入式链表的讲解,当然,在内核中真正的代码使用了大量的trick这里并没有说明,感兴趣的话可以看相关的文章。