自旋锁适合锁持有时间极短的场景;因其忙等待特性,仅适用于临界区执行迅速、无睡眠可能且CPU资源充足的多核环境。

自旋锁适合什么场景?spin_lock 不是“更快”的代名词
自旋锁只在锁持有时间极短(通常 while (!try_acquire()) { cpu_relax(); },CPU 一直跑空循环,不交出调度权。
常见错误现象:在可能触发页缺失、系统调用或内存分配的临界区里用 spin_lock —— 这会导致 CPU 白白烧着,还拖慢其他核上的任务。
- 适用场景:中断上下文、内核中已禁用抢占的原子路径、纯 CPU 计算型临界区(如更新一个计数器)
- 不适用场景:任何可能调用
kmalloc(GFP_KERNEL)、访问用户内存、等待 I/O 或调用schedule()的地方 - 参数差异:
spin_lock(&lock)会禁用本地中断(防止中断 handler 抢占并死锁),而spin_lock_bh()只禁用 softirq/bh,选错会引发隐性竞态
互斥锁为什么默认更安全?mutex_lock 的代价藏在哪
mutex_lock 是睡眠锁,拿不到就主动让出 CPU,调度器换别的线程跑。这避免了 CPU 浪费,但引入了上下文切换开销和调度延迟。
容易踩的坑:在中断上下文或禁止睡眠的区域(比如 atomic 上下文、RCU read-side)调用 mutex_lock,会直接触发 BUG: scheduling while atomic 错误。
- 适用场景:进程上下文、临界区可能较长(微秒到毫秒级)、需要做内存分配或文件 I/O 的逻辑
- 性能影响:单次
mutex_lock在无竞争时约 20–50 纳秒;有竞争时,一次唤醒+调度可能耗时几十微秒甚至更多 - 注意
mutex_trylock():它不睡眠,但失败后你得自己处理重试或降级逻辑,别当成spin_trylock()的平替
别硬选 —— Linux 内核里怎么动态切换?rwsem 和 rcu_read_lock 是替代选项
当读多写少,或者临界区语义允许延迟可见,硬套 spin_lock 或 mutex_lock 都是过杀。这时候得看数据访问模式,而不是只盯“锁快不快”。
典型误判:为保护一个被频繁读取的配置结构体,用 spin_lock —— 实际上 struct rw_semaphore 的读端几乎无开销,写端才阻塞,整体吞吐反而更高。
-
rwsem:读并发安全,写独占;比mutex多一点元数据,但读路径不进内核调度器 -
rcu_read_lock():零锁开销,但要求写端用call_rcu()延迟释放旧数据,适用于指针替换类操作(如路由表、模块列表) - 混合策略:小粒度用
spin_lock,大块逻辑外包给mutex,中间状态用atomic_t或lockless ringbuffer
实测前先问自己三个问题
很多开销争议其实源于没看清真实瓶颈。不是锁类型决定性能,而是锁保护的那段代码本身是否合理。
- 这段临界区平均执行多久?用
kprobe+perf record -e sched:sched_stat_sleep,sched:sched_stat_runtime看实际阻塞/运行时间分布 - 锁竞争频率高吗?
/proc/lock_stat(需开启 CONFIG_LOCK_STAT)能暴露spin_lock的等待次数和总纳秒数 - 有没有办法把锁粒度变细、挪出慢路径、或用 per-CPU 变量避开争抢?例如把全局计数器换成
struct this_cpu_counter
真正难的从来不是选 spin_lock 还是 mutex_lock,而是确认你锁住的那几行代码,是不是真的需要被锁住。











