1. 项目概述
在Linux内核开发中,链表是最基础也是最常用的数据结构之一。不同于用户空间的链表实现,内核链表采用了一种独特而高效的设计方式。我花了整整三个月时间研读内核源码中的链表实现,期间踩过不少坑,也积累了一些实战经验。今天就来聊聊内核中单链表的具体实现和操作技巧。
内核链表的设计哲学是"最小化内存占用"和"最大化操作效率"。与常见的双向链表不同,单链表在内存敏感的场景下更有优势。比如在进程调度、设备驱动管理等场景中,单链表的使用非常普遍。掌握它的实现细节,对理解内核工作机制和进行驱动开发都至关重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 内核单链表的数据结构
2.1 基本结构定义
在内核源码的include/linux/list.h中,单链表节点的定义出奇地简单:
c复制struct hlist_node {
struct hlist_node *next;
struct hlist_node **pprev;
};
这个设计有几点值得注意:
next指针指向下一个节点,这是单链表的典型特征pprev是一个二级指针,它指向前一个节点的next指针- 整个结构只有两个指针,内存占用极小
为什么使用二级指针?这是为了在删除节点时不需要判断是否是头节点,统一了操作逻辑。这个设计在内核中很常见,值得学习。
2.2 链表头结构
对应的链表头定义如下:
c复制struct hlist_head {
struct hlist_node *first;
};
头节点只包含一个指向第一个元素的指针。这种分离设计使得链表头的大小减半,在哈希表等需要大量链表头的场景下能显著节省内存。
3. 单链表的核心操作
3.1 初始化链表
初始化分为头节点和普通节点两种情况:
c复制// 初始化头节点
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT
// 初始化普通节点
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->
