spinlock 与自旋锁

这页讲的是:有些共享状态必须立刻保护,但当前环境又不允许睡下等待,这时内核常会用 spinlock 这种“先别动,我很快就好”的方式。学这页的重点,是理解自旋锁的核心不是“锁住资源”这么泛,而是“在不能睡眠的短临界区里,用忙等换取原子化的执行窗口”。

这块是什么

spinlock 与自旋锁,讲的是 Linux 怎样在一些很短、很敏感、而且不能睡眠的执行路径里,保护共享状态不被并发访问。它关注的是“先让别的执行别进来,我马上处理完”,而不是让等待者舒服地睡下慢慢等。

可以把它理解成:你要在窄门口快速搬一下东西,别人先别挤进来;如果很快就结束,让他们站着等一小会儿反而比安排所有人去休息室再叫回来更划算。

它负责什么

保护很短的共享临界区

  • 有些状态变化必须一口气做完
  • 中途不能让别的 CPU 或上下文插进来
  • 自旋锁适合保护这种短小而敏感的片段
  • 把共享修改压进一个紧凑执行窗口

适配不能睡眠的环境

  • 有些上下文里根本不允许阻塞等待
  • 这时只能让竞争者短暂忙等
  • 用 CPU 空转换取语义上的立即保护
  • 让原子上下文也能有正式同步手段

配合中断与本地时序约束

  • 不只是多核并发,有时还要考虑本地中断或下半部重入
  • 锁语义常和中断关闭范围一起考虑
  • 让“谁会同时碰这份状态”被认真算清楚
  • 避免本地路径自己打断自己

为什么它不是“更快的 mutex”

如果想得太简单会怎样真正关键在哪
觉得自旋锁只是更轻量会忽略它和 mutex 的最大差别其实是等待语义不同。一个忙等不睡,一个会让等待者睡下。
把它用在很长路径上会让 CPU 白白空转,延迟和吞吐一起变差。自旋锁最怕临界区过长。
只看多核竞争会漏掉本地中断或下半部也可能重入同一状态。锁设计常常同时在防跨 CPU 和防本地重入。
以为拿了锁就万事大吉会忽略上下文约束:拿着自旋锁时通常不能做会睡眠的事。锁不仅保护数据,也在约束代码写法。

关键概念

概念现在怎么理解
spinlock竞争失败时不睡眠,而是在原地短暂忙等的锁。
忙等等待者持续占着 CPU 检查锁是否释放,而不是阻塞挂起。
短临界区适合自旋锁保护的通常是很快就能完成的小段共享修改。
原子上下文不能阻塞睡眠的执行环境,自旋锁经常出现在这里。
本地中断约束有时不仅要防别的 CPU,还要防本地事件在不合适时机重入。

为什么重要

常见误解

它不负责什么

和其他模块的关系

相关模块关系
preemption 与抢占某些本地连续性假设要求拿锁时同时避免当前执行被不合适地切走。
中断与下半部很多自旋锁使用场景都和中断上下文或底半部重入密切相关。
mutex两者都在做互斥,但一个适合不能睡的短路径,一个适合能睡的较长等待。
per-CPU data缩小共享范围常常是避免到处上自旋锁的另一种思路。

读完这页后,你应该能回答

后面适合继续问:spin_lock、spin_lock_irqsave 和禁止抢占最容易混在哪?什么时候把共享状态改成 per-CPU 比继续加自旋锁更好?为什么拿着自旋锁去做可能睡眠的事情会出大问题?