std::lock_guard
和 std::unique_lock
是 C++11 提供的两种用于管理互斥锁 (std::mutex
) 的类,它们简化了锁的使用,确保锁的自动释放。
1. std::lock_guard
与 std::unique_lock
的区别
std::lock_guard
- 功能:
std::lock_guard
是一种简单的锁管理器,用于在其生存期内锁定互斥锁,并在对象销毁时自动解锁。 - 使用场景:适用于那些锁定后不需要解锁、重新锁定、延迟锁定或转移锁所有权的场景。
- 特点:
-
- 不可转移:
std::lock_guard
不能转移所有权。 - 不支持延迟锁定:一旦创建对象时必须立即锁定。
- 不支持显式解锁:锁的解锁只能通过对象析构来完成。
- 不可转移:
- 语法示例:
std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
// 在这个作用域内,互斥锁是锁定的
} // 作用域结束时,自动解锁
std::unique_lock
- 功能:
std::unique_lock
是一个功能更为丰富的锁管理器,支持更多的锁管理操作,例如延迟锁定、显式解锁/重新锁定、锁的转移等。 - 使用场景:适用于那些需要更灵活的锁管理操作的场景,例如需要延迟锁定、条件变量的等待等。
- 特点:
-
- 可转移:
std::unique_lock
可以通过移动构造函数或移动赋值运算符转移锁的所有权。 - 支持延迟锁定:可以在创建
std::unique_lock
对象时不立即锁定,而是在之后的某个时刻调用lock()
函数来锁定。 - 支持显式解锁/重新锁定:可以通过
unlock()
和lock()
方法手动解锁和重新锁定。
- 可转移:
- 语法示例:
std::mutex mtx;
{
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟锁定
// 在这个作用域内,互斥锁未锁定
lock.lock(); // 手动锁定
// 执行一些操作
lock.unlock(); // 手动解锁
// 其他操作
} // 作用域结束时,自动解锁(如果没有显式解锁)
2. std::lock_guard
和 std::unique_lock
与 std::mutex
的关系
std::mutex
是互斥锁的基本实现,它可以单独使用来显式地锁定和解锁资源。例如:
std::mutex mtx;
mtx.lock();
// 访问共享资源
mtx.unlock();
然而,这种方式容易出现问题,例如忘记解锁或在异常发生时导致死锁。
std::lock_guard
和std::unique_lock
是基于 RAII(资源获取即初始化)原则的包装器类,它们在构造时锁定互斥锁,在析构时自动解锁,从而避免了忘记解锁的风险。这两者都依赖于std::mutex
,但提供了不同程度的封装和功能:
-
std::lock_guard
是一种简单且高效的方式,适合那些不需要复杂锁管理的场景。std::unique_lock
提供了更灵活的控制,适合需要在锁的生命周期内执行复杂操作的场景。
总结
std::lock_guard
:简单、高效,适用于不需要解锁、重新锁定或转移锁所有权的场景。std::unique_lock
:功能强大,支持延迟锁定、显式解锁/重新锁定和锁的转移,适合需要更灵活控制的场景。std::mutex
:是底层的互斥锁实现,可直接使用,但通常与std::lock_guard
或std::unique_lock
结合使用,以避免手动管理锁带来的复杂性。
选择 std::lock_guard
还是 std::unique_lock
取决于你对锁的管理需求。