本专栏以"内核为什么需要这么多种锁,每一种到底怎么实现"为主线,从最底层的原子操作与内存屏障出发,逐层向上:先讲不睡眠的自旋类锁(spinlock/qspinlock/qrwlock/osq_lock),再讲可阻塞的睡眠类锁(mutex/rwsem),最后落到无锁与特化原语(ww_mutex/seqcount)。每一篇统一回答四个问题——守护什么、为什么用它、怎么实现(源码级)、误用与调试。本专栏与《MMU Notifier 深入解析》互为地基与用例:通用锁原理在此,GPU/HMM 场景应用见 mmu-notifier 专栏。
第一部分:地基
所有锁最终都建立在两块基石上:原子操作保证"读-改-写"不可分割,内存屏障约束多核间的可见顺序。不理解 acquire/release 语义,就无法理解任何一把锁的正确性。本部分是通读全专栏的前提。
| 1 | 原子操作与内存屏障:一切锁的地基 | atomic_t/atomic64_t 的实现、READ_ONCE/WRITE_ONCE、smp_mb/rmb/wmb、acquire/release/fence 语义,以及"锁 = 原子操作 + 屏障 + 等待策略"的总纲。源码:include/linux/atomic.h、Documentation/memory-barriers.txt |
第二部分:自旋类(不睡眠)
临界区极短、且可能处于不可睡眠上下文(中断、原子区)时,应当自旋而非睡眠。本部分从最朴素的 spinlock 讲到 qspinlock 如何用 MCS 队列消除多核 cache-line 争用,再看读写自旋锁 qrwlock 与乐观自旋的公共底座 osq_lock。
| 2 | spinlock 与 qspinlock:从测试-设置到 MCS 队列 | spinlock_t 的语义与不睡眠约束,qspinlock 的四字节状态编码与 MCS 队列如何把"所有 CPU 争一条 cache line"降为"各自自旋在本地节点"。源码:kernel/locking/spinlock.c、kernel/locking/qspinlock.c、kernel/locking/mcs_spinlock.h |
| 3 | rwlock 与 qrwlock:读者写者的自旋权衡 | 读多写少场景下的读写自旋锁,qrwlock 的读写计数编码与写者优先策略如何避免写者饥饿。源码:kernel/locking/qrwlock.c |
| 4 | osq_lock:乐观自旋队列 | MCS 变体,mutex/rwsem 乐观自旋的底座:持锁者仍在运行时排队自旋而非立即睡眠,兼顾低延迟与可扩展。源码:kernel/locking/osq_lock.c、kernel/locking/mcs_spinlock.h |
第三部分:睡眠类(可阻塞)
临界区较长、或临界区内需要阻塞(等 I/O、等 DMA、拿其它睡眠锁)时,应当睡眠让出 CPU。本部分拆解两把最主流的睡眠锁:mutex 的乐观自旋 + handoff 防饥饿,以及 rwsem 的读写计数编码与 writer 偷锁——后者正是 mmu-notifier 专栏附篇里 drm_gpusvm 那把 notifier_lock 的本体。
| 5 | mutex:乐观自旋与 handoff | mutex 的 owner 指针 + MUTEX_FLAG 低位编码、乐观自旋(持锁者在跑就自旋)、handoff 机制如何防止长期饥饿。源码:kernel/locking/mutex.c、kernel/locking/mutex.h |
| 6 | rwsem:读写信号量的计数编码与偷锁 | count 字段的读者计数/写者位/等待位编码、writer 乐观偷锁、读者与写者的公平性。呼应 mmu-notifier 专栏附篇《drm_gpusvm 的 notifier_lock 深解》。源码:kernel/locking/rwsem.c、include/linux/rwsem.h |
第四部分:无锁与特化
这两篇跳出"互斥"范式:ww_mutex 解决"一次要拿多把锁"的死锁避免,是 DRM/dma-resv 与 GPU 显存驱逐的基石;seqcount 则用序号碰撞重试实现读侧几乎零开销的一致性检查,与 mmu-notifier 专栏第 3 章的 invalidate_seq 一脉相承。
| 7 | ww_mutex:wound/wait 死锁避免 | 多锁获取场景的死锁避免算法(wound-wait),ww_acquire_ctx 时间戳、-EDEADLK 回退重试,直连 DRM dma_resv 与 GPU 显存驱逐。源码:kernel/locking/ww_mutex.h、kernel/locking/ww_rt_mutex.c、kernel/locking/test-ww_mutex.c |
| 8 | seqlock 与 seqcount:序号驱动的无锁读 | 读侧 begin/retry 碰撞重试、写侧奇偶序号、内存屏障配对,以及它与 mmu-notifier invalidate_seq 的同源关系。源码:include/linux/seqlock.h |
扩展部分
至此,核心八篇已沿"地基 → 自旋类 → 睡眠类 → 无锁与特化"一条主干走通,并在 GPU/HMM 场景落地。但主干为求聚焦,刻意搌置了三条支线:睡眠锁的历史前身、比"重试"更彻底的无锁范式、以及"验证与调试锁"本身的基础设施。下列扩展篇正是来补齐这些留白——每一篇都从某一核心章节延伸而出,不再从零铺陈,而是回答"在主干之外,它多补了哪一块":
| 9 | 睡眠锁 | semaphore:最朴素的计数信号量 | kernel/locking/semaphore.c,无 owner 的计数信号量,对比 mutex(第 5 章)看历史演进、彻底收口"名字误会" |
| 10 | 无锁 | RCU 与 SRCU 综述 | kernel/rcu/,宽限期语义,补上 seqcount(第 8 章)"含指针须叠加 RCU"的伏笔,深挖回指 mmu-notifier 专栏 12.3 |
| 11 | 工具 | lockdep 死锁检测原理 | kernel/locking/lockdep.c,持有链与有向图环检测,前 12 章"误用与调试"背后的同一台引擎,回指 mmu-notifier 专栏 12.7 的伪锁 |
| 12 | 工具 | locktorture:锁实现的压力验证 | kernel/locking/locktorture.c,如何证明一把锁实现正确,呼应 ww_mutex(第 7 章)的 test-ww_mutex |
说明:
技术交流和投稿,欢迎加入社区:GPUers。
网硕互联帮助中心
-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/09/20260912064130-6aa4f41aa1d1a-220x150.png)



评论前必须登录!
注册