lock_guard适用于简单场景,构造时加锁、析构时解锁,不支持手动控制;unique_lock更灵活,支持延迟加锁、手动加解锁、条件变量配合及所有权转移,但性能开销略高。

lock_guard 和 unique_lock 都是 C++ 中用于管理互斥量(mutex)的 RaiI(资源获取即初始化)类,确保在作用域结束时自动释放锁。虽然功能相似,但它们在灵活性、使用场景和性能上存在明显区别。
基本特性对比
lock_guard 是最简单的锁管理工具,构造时加锁,析构时解锁,不支持手动控制或转移所有权。unique_lock 更加灵活,除了具备 lock_guard 的自动管理能力外,还支持延迟加锁、手动加锁/解锁、条件变量配合以及锁的所有权转移。
主要差异体现在以下几个方面:
是否支持延迟加锁
lock_guard 在构造时必须立即对 mutex 加锁,无法延迟:
std::lock_guard<std::mutex> lg(mtx); // 立即加锁
unique_lock 可以选择是否在构造时加锁:
立即学习“C++免费学习笔记(深入)”;
std::unique_lock<std::mutex> ul(mtx, std::defer_lock); // 不加锁
之后可以手动调用 ul.lock() 或 ul.unlock() 控制锁状态。
是否支持手动解锁
lock_guard 一旦加锁,只能等到对象生命周期结束才释放锁,中间无法临时解锁。unique_lock 允许在作用域内临时解锁,便于执行耗时操作或避免死锁:
– ul.unlock(); 手动释放锁
– ul.lock(); 再次获取锁
这种能力在需要长时间处理非共享数据时非常有用。
能否与条件变量配合使用
std::condition_variable 的 wait() 方法要求传入一个 unique_lock,因为它需要在等待期间临时释放锁。
cond.wait(ul); // ul 是 unique_lock,合法
lock_guard 不支持此操作,不能用于条件变量的等待流程。
是否支持锁的移动和转移
unique_lock 支持移动语义,可以在函数间传递锁的所有权:
std::unique_lock<std::mutex> getLock() { return std::unique_lock<std::mutex>(mtx); }
lock_guard 不可移动也不可复制,锁的作用范围严格限定在定义它的作用域内。
性能开销对比
lock_guard 更轻量,没有额外状态记录,编译器优化更好,运行时开销最小。unique_lock 因为支持更多功能(如是否持有锁的状态标记),内部有额外成员变量,性能略低。如果只需要简单的作用域锁,优先使用 lock_guard。
基本上就这些。简单场景用 lock_guard,复杂控制用 unique_lock。不复杂但容易忽略的是:别为了“以后扩展”而滥用 unique_lock,能用 lock_guard 就用它。


