mutex 是 c++ 基础互斥锁,不支持递归和超时;lock_guard 是 RaiI 锁管理器,构造时加锁、析构时自动解锁,确保异常安全,不可复制或手动解锁。

mutex 是 C++ 中用于保护共享资源的互斥量,而 lock_guard 是一个 RAII 风格的锁管理器,它在构造时自动加锁、析构时自动解锁,避免手动加锁/解锁遗漏导致的死锁或数据竞争。
mutex:最基础的互斥锁
std::mutex 是标准库提供的轻量级互斥锁,只能被一个线程持有。它不支持递归(同一线程重复 lock 会死锁),也不支持超时等待(如需这些功能,可用 std::recursive_mutex 或 std::timed_mutex)。
常用操作:
-
m.lock():阻塞式加锁,直到成功获取锁 -
m.unlock():释放锁(必须由当前持有锁的线程调用) -
m.try_lock():非阻塞尝试加锁,返回true表示成功
lock_guard:自动管理锁的“守卫”
std::lock_guard 是最常用的锁包装器,基于 RAII 原则,确保锁的生命周期与作用域绑定——进作用域即加锁,出作用域即解锁(即使发生异常也安全)。
立即学习“C++免费学习笔记(深入)”;
典型用法:
std::mutex mtx; int shared_data = 0; void safe_increment() { std::lock_guard<std::mutex> guard(mtx); // 构造即 lock() ++shared_data; // 访问临界区 } // guard 离开作用域,自动 unlock()
注意:lock_guard 不可复制、不可转移,只支持移动(但通常不需要移动);也不能手动调用 unlock() —— 它的设计就是“全托管”。
常见误用与注意事项
以下写法容易引发问题:
- 手动调用
unlock()后又让lock_guard析构 → 未定义行为 - 把
lock_guard声明在函数开头,但临界区实际只在后面几行 → 锁持有时间过长,降低并发性 - 多个 mutex 加锁顺序不一致 → 可能导致死锁(建议始终按固定地址/变量名顺序加锁)
- 在持有 mutex 期间调用可能阻塞或抛异常的函数(如 I/O、new)→ 延长锁持有时间,或异常导致提前退出但锁已释放(其实
lock_guard仍安全,但逻辑可能出错)
更灵活的选择:unique_lock
如果需要延迟加锁、条件变量配合、或手动控制解锁时机,可用 std::unique_lock。它比 lock_guard 更重,但功能更全:
- 支持默认构造(不关联 mutex)、
defer_lock(构造时不加锁) - 可多次 lock/unlock,支持移动,能和
std::condition_variable配合 - 性能略低,非必要时优先用
lock_guard
基本上就这些。用好 mutex + lock_guard 就能解决大部分线程安全问题,关键在于:锁粒度要小、作用域要准、别跨函数传递裸 mutex。