链表是嵌入式软件开发中最基础的数据结构之一,其设计采用嵌入式链表节点的思想,实现了高度通用的链表管理机制。以下是核心原理和操作的全面解析:
struct list_head {
struct list_head *next, *prev; // 双向指针
};
设计特点:
// 静态初始化
LIST_HEAD(my_list);
// 动态初始化
struct list_head my_list;
INIT_LIST_HEAD(&my_list);
// 头插法(插入到head之后)
list_add(struct list_head *new, struct list_head *head);
// 尾插法(插入到head之前)
list_add_tail(struct list_head *new, struct list_head *head);
图示:
头插法: head → new → node1 → node2
尾插法: node1 → node2 → new → head
// 基础删除
list_del(struct list_head *entry);
// 安全删除(删除后初始化节点)
list_del_init(struct list_head *entry);
注意:删除后节点指针被设为LIST_POISON1/2
(用于调试)
// 基础遍历
#define list_for_each(pos, head) \
for (pos = (head)->next; 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)
// 反向遍历
list_for_each_prev(pos, head)
list_entry
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
实现原理:
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
参数解析:
ptr
:链表节点指针(如&data->list
)type
:父结构体类型(如struct my_data
)member
:链表成员名(如list
)计算过程:
member
在type
中的偏移量(offsetof
)// 链表判空
list_empty(const struct list_head *head)
// 节点移动
list_move(struct list_head *list, struct list_head *head) // 移动到head后
list_move_tail(struct list_head *list, struct list_head *head) // 移动到head前
// 链表合并
list_splice(const struct list_head *list, struct list_head *head) // 合并到head后
// 1. 定义数据结构
struct task_info {
pid_t pid;
char name[16];
struct list_head list; // 嵌入链表节点
};
// 2. 初始化链表头
LIST_HEAD(task_list);
// 3. 添加节点
struct task_info *task1 = kmalloc(sizeof(*task1), GFP_KERNEL);
task1->pid = 1001;
strcpy(task1->name, "init");
INIT_LIST_HEAD(&task1->list);
list_add_tail(&task1->list, &task_list); // 添加到链表尾部
// 4. 遍历链表
struct list_head *pos;
struct task_info *task;
list_for_each(pos, &task_list) {
task = list_entry(pos, struct task_info, list);
printk("PID: %d, Name: %s\n", task->pid, task->name);
}
// 5. 安全删除所有节点
struct list_head *n;
list_for_each_safe(pos, n, &task_list) {
task = list_entry(pos, struct task_info, list);
list_del(pos);
kfree(task);
}
类型无关性:
list_head
,与具体数据类型解耦container_of
实现类型安全转换内存高效:
O(1)时间复杂度:
// list_add内部实现
new->next = head->next;
new->prev = head;
head->next->prev = new;
head->next = new;
循环链表设计:
多链表嵌入:
struct process {
struct list_head ready_list; // 就绪队列
struct list_head wait_list; // 等待队列
// ...
};
哈希链表:
struct hlist_head *htable; // 哈希表头
struct hlist_node node; // 哈希节点
RCU安全遍历:
list_for_each_entry_rcu(pos, head, member)
删除安全:
_safe
版本内存屏障:
smp_rmb()
/smp_wmb()
保证可见性对齐要求:
container_of
依赖结构体成员对齐,不可随意填充这种链表设计被广泛应用于操作系统内核(如进程调度、文件系统、网络协议栈等),其通用性和高效性使其成为系统编程的经典范式。理解其原理对深入操作系统和嵌入式开发至关重要。