std::lock_guard 和 std::unique_lock 都是 C++ 标准库 <mutex> 中提供的用于管理互斥体(mutex)的 RAII(Resource Acquisition Is Initialization)风格的类。它们的主要目标都是确保互斥体在适当的时候被锁定和解锁,以避免忘记释放锁或多次锁定同一互斥体导致的死锁等问题。然而,它们在功能和使用场景上存在一些差异。
std::lock_guard
std::lock_guard 是一个简单的互斥体包装器,它在构造时锁定互斥体,并在析构时自动解锁。std::lock_guard 不提供手动解锁互斥体的功能,一旦创建,它就会在对象的生命周期内保持锁定状态。
特点:
- 自动锁定和解锁:无需显式调用锁定或解锁函数。
- 不可复制:std::lock_guard对象不可复制,但可移动。
- 简单易用:适用于简单的锁定/解锁场景。
示例:
std::mutex mtx;  
void safe_increment() {  std::lock_guard<std::mutex> guard(mtx);  // 临界区,互斥体 mtx 被锁定  // ...  
} // 离开作用域时,guard 析构,mtx 自动解锁std::unique_lock
std::unique_lock 是一个更灵活的互斥体包装器,它提供了更多的控制选项,如手动锁定、解锁、延迟锁定、尝试锁定等。
特点:
- 手动锁定和解锁:可以通过调用 lock(),unlock(),try_lock()等成员函数来控制锁定状态。
- 可延迟锁定:可以在创建 std::unique_lock对象时不立即锁定互斥体,而是在需要时手动锁定。
- 可与 std::condition_variable配合使用:std::unique_lock可以与std::condition_variable一起使用,实现线程间的条件等待和通知。
- 可复制和移动(但复制后原始对象将不再拥有互斥体的所有权):std::unique_lock对象可以复制和移动,但需要注意所有权的变化。
示例:
std::mutex mtx;  
std::condition_variable cv;  
bool ready = false;  void worker_thread() {  std::unique_lock<std::mutex> lock(mtx);  cv.wait(lock, []{return ready;}); // 等待条件满足,同时释放锁  // ... 执行任务  
}  void signal_ready() {  {  std::lock_guard<std::mutex> lock(mtx);  ready = true;  } // 释放锁  cv.notify_one(); // 通知等待的线程  
}总结
- 如果你只需要简单的锁定/解锁操作,并且确保在离开作用域时自动解锁,那么 std::lock_guard是更好的选择。
- 如果你需要更多的控制选项,如手动锁定、解锁、延迟锁定、与 std::condition_variable配合使用等,那么std::unique_lock是更合适的选择。
白话
 std::lock_guard在析构的时候,指定解锁,想提前解锁也解锁不了。而std::unique_lock可以随时控制解锁。可以理解为std::lock_guard是一个std::unique_lock的简化版本,虽然不够灵活但可以覆盖大部分使用场景,且简单、安全、有效