在 C++ 中,锁分为两类:互斥量(Mutex,即锁本身) 和 锁管理类(Lock Managers,即 RAII 包装器)。
A. 锁本身 (std::mutex 家族)
这些是真正的锁对象,位于 <mutex> 头文件。
- std::mutex**(最常用)**
-
- 特点:独占互斥锁。一个线程拿到了,其他线程就得等。
- 方法 :
lock()(上锁,失败则阻塞)、unlock()(解锁)、try_lock()(尝试上锁,失败返回 false,不阻塞)。 - 注意:不可递归上锁(同一个线程不能连续 lock 两次,否则死锁)。
- std::recursive_mutex**(递归锁)**
-
- 特点 :允许同一个线程多次上锁。
- 场景:比如一个递归函数,每一层都需要加锁;或者函数 A 调函数 B,A 和 B 都要加同一把锁。
- 代价:比普通 mutex 慢,尽量少用。
- std::timed_mutex**(超时锁)**
-
- 特点:在拿不到锁时,可以设置等待时间,而不是无限死等。
- 方法 :
try_lock_for(std::chrono::milliseconds(100))。
- std::shared_mutex**(读写锁,C++17 引入)**
-
- 特点:解决"读多写少"的性能问题。
- 机制:
-
-
- 共享锁 (Shared Lock):多个线程可以同时加这个锁(只读操作)。
- 独占锁 (Exclusive Lock):只有一个线程能加这个锁(写操作),且此时不能有其他人读。
-
B. 锁管理类 (RAII Wrappers) ------ 这才是你该用的东西
切记: 尽量不要手动调用 mutex.lock() 和 unlock()。一旦中间抛出异常,或者你忘记 unlock,程序就死锁了。
使用以下类来自动管理锁的生命周期:
- std::lock_guardstd::mutex****(轻量级,简单粗暴)
-
- 机制 :构造时立马
lock,析构时立马unlock。 - 缺点:中途不能手动解锁,必须等到作用域结束。
- 场景:简单的临界区保护。
- 机制 :构造时立马
- std::unique_lockstd::mutex****(灵活,功能全)
-
- 机制 :构造时
lock(也可以选择不立马 lock),析构时unlock。 - 优点:
- 机制 :构造时
-
-
- 可以中途手动
unlock()(比如为了让出 CPU 一会儿)。 - 配合条件变量 ( std::condition_variable**) 必须用它**。
- 支持"延迟锁定"(defer_lock)。
- 可以中途手动
-
-
- 代价:比 lock_guard 稍微重一点点。
代码示例:unique_lock 的灵活性
std::mutex mtx;
void complex_task() {
// 1. 构造时加锁
std::unique_lock<std::mutex> lock(mtx);
// 操作共享数据...
// 2. 中途临时解锁(比如要做一些耗时的、不涉及共享数据的操作)
lock.unlock();
// ... 做耗时操作 ...
// 3. 重新加锁
lock.lock();
// 4. 函数结束,自动解锁
}