首页/操作系统/02-process/互斥锁 🔗 在 Obsidian 中打开
操作系统 · 02-process

互斥锁

重要度 ★★★★ 互斥锁mutex自旋锁忙等锁
速查
互斥锁(Mutex)保证同一时刻只有一个线程进入临界区:自旋锁获取失败则忙等(临界区短),阻塞锁获取失败则释放 CPU(临界区长)。

速查

项目
定义用于保护临界区的锁,保证同一时刻只有一个线程访问
两种实现自旋锁(忙等)、非自旋锁(阻塞)
操作lock() 获取锁、unlock() 释放锁
适用场景临界区短 → 自旋锁;临界区长 → 阻塞锁

核心概念

互斥锁(Mutex Lock)是最基本的同步原语,用于保证同一时刻只有一个线程(或进程)可以进入临界区。

两种实现方式

1. 自旋锁(Spinlock)

  • 获取锁失败时,线程忙等(while 循环检查锁状态)
  • 优点:无上下文切换开销
  • 缺点:浪费 CPU(忙等)
  • 适用:临界区很短(如几条指令),等待时间短

2. 阻塞锁(非自旋锁)

  • 获取锁失败时,线程阻塞(释放 CPU,加入等待队列)
  • 优点:不浪费 CPU
  • 缺点:上下文切换开销
  • 适用:临界区较长,等待时间长
注意互斥锁的 acquire/release 操作必须是原子的,通常用 TestAndSet 或 CAS 实现。

关键性质

对比项自旋锁阻塞锁
等待方式忙等(while 循环)阻塞(释放 CPU)
CPU 利用低(忙等浪费)高(让出 CPU)
上下文切换有(切换开销)
适用场景临界区短临界区长
多核优势有(无切换开销)一般

常见考法

考法解题套路
自旋锁 vs 阻塞锁临界区短 → 自旋锁;临界区长 → 阻塞锁
lock/unlock 原子性acquire 和 release 必须是原子操作(用 TAS/CAS 实现)
互斥锁 vs 信号量互斥锁只允许一个线程进入;信号量可允许多个(计数信号量)
死锁问题同一线程两次 lock 同一 mutex → 死锁

易错点

注意
  • 互斥锁的 lock() 和 unlock() 必须由同一线程执行(谁加锁谁解锁)
  • 信号量的 wait/signal 可以由不同进程执行——这是与互斥锁的关键区别
  • 同一线程对同一 mutex两次 lock 会导致死锁
  • 二元信号量(值为 0 或 1)可以实现互斥,但语义不同于 mutex
  • 自旋锁在单处理器上必须关闭中断,否则忙等的线程永远不让出 CPU

核心结论

必背
  1. 互斥锁是最基本的同步工具,保证临界区互斥访问
  2. 自旋锁适合临界区短的场景,阻塞锁适合临界区长的场景
  3. 互斥锁的 lock/unlock 必须由同一线程执行
  4. 互斥锁底层由硬件原子指令(TAS/CAS)实现
  5. mutex vs 信号量:mutex 用于互斥,信号量用于同步和互斥

记忆卡片

自旋锁和阻塞锁的核心区别?
自旋锁忙等(浪费 CPU),阻塞锁释放 CPU(有切换开销)。
什么场景用自旋锁?
临界区很短、等待时间短、多核系统。
互斥锁的 lock/unlock 要求?
必须由同一线程执行(谁加锁谁解锁)。
mutex 和信号量的区别?
mutex 只允许一个线程,谁加锁谁解锁;信号量可允许多个,wait/signal 可不同线程。
两次 lock 同一 mutex?
死锁——线程自己把自己锁住。

交互动画 · 自旋锁 vs 阻塞锁

CPU 执行临界区 mutex 锁已被占用 等待队列阻塞线程 线程 T
点击「自旋锁」或「阻塞锁」查看获取失败时线程的不同行为
自旋:忙等占用 CPU;阻塞:让出 CPU 进入等待队列
获取锁失败时,自旋锁持续轮询(无切换开销但浪费 CPU),阻塞锁则释放 CPU 进入等待队列(有切换开销但节省 CPU)。

相关知识点

critical-section-and-resource condition-variable

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。