在spinlock临界区内使用list_for_each_entry系列遍历链表是否安全?
回答
安全性与合规性结论
你的第一版代码是安全且符合内核编程规范的,反而是你调整后的第二版写法存在明确的线程安全问题。
1. 第一版代码无安全问题
你最初将完整的遍历、判断、增删逻辑都包裹在spin_lock(&mylock)和spin_unlock(&mylock)之间的实现是完全正确的:
- 所有对共享链表的读操作(遍历、匹配目标元素)、写操作(删除旧元素、插入新元素)都在同一个临界区内完成,全程持有自旋锁,其他线程无法同时修改链表结构,不会出现竞态条件
- 遍历用
list_for_each_entry_safe的选择也适配你的需求,这个宏专门用于遍历过程中需要修改链表(删除节点)的场景,只要链表在临界区内不会被其他线程改动,遍历逻辑就不会出错 - 仅有的语法问题是
bool added = false末尾漏了分号,补全即可。
2. 遍历逻辑放在自旋锁临界区完全合规
这种写法是内核并发控制的标准实现方式,不需要有顾虑:
- 自旋锁的设计本身就允许临界区包含遍历逻辑,只要你能保证临界区执行时间足够短:如果你的练习场景中链表长度不大(比如百级以内节点),单次遍历的耗时完全在自旋锁允许的临界区时长范围内,不会引发调度或软中断超时问题
- 如果后续遇到链表极长、读多写少的场景,可以换成读写锁、RCU等更适配的同步机制,但你的练习场景下全逻辑包自旋锁是最简单、最稳妥的实现。
3. 第二版写法的问题本质
你调整后的拆分加锁写法核心问题有两个:
- 遍历操作本身没有被锁保护:你在未持有锁的情况下就开始遍历共享链表,其他线程可能在遍历过程中修改链表结构,轻则遍历漏节点/重复遍历,重则直接触发内存访问异常panic
- 你标注的间隙竞态是次生问题:遍历结束后、再次加锁前的空档期,其他线程可以插入同值节点,导致当前线程判断逻辑失效,插入重复元素。
内容的提问来源于stack exchange,提问作者Shisui
相关产品推荐
相关产品推荐

