- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
std::lock_guard 是 C++11 引入的一个 RAII(Resource Acquisition Is Initialization)风格的锁管理类,用于自动管理互斥锁(mutex)的加锁和解锁,确保在任何情况下(包括异常)都能正确释放锁。
核心作用
- 构造时加锁
- 析构时自动解锁
- 防止死锁和资源泄漏
- 异常安全
✅ 它是最简单、最安全的互斥锁管理方式,适用于大多数临界区保护场景。
头文件
#include <mutex>
基本语法
std::lock_guard<std::mutex> lock(mutex_object);
- std::mutex:可以是任何标准互斥类型(如 std::mutex, std::recursive_mutex)
- lock:作用域内的锁对象,名字可自定义
- mutex_object:已经定义的互斥量
使用示例
示例 1:保护共享变量
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
using namespace std;int counter = 0;
std::mutex mtx; // 全局互斥锁void safe_increment(int n) {for (int i = 0; i < n; ++i) {// { 作用域开始std::lock_guard<std::mutex> lock(mtx); // 构造时加锁counter++; // 安全访问共享资源// } 作用域结束,lock 析构,自动解锁}
}int main() {vector<thread> threads;// 创建 4 个线程for (int i = 0; i < 4; ++i) {threads.emplace_back(safe_increment, 10000);}// 等待所有线程完成for (auto& t : threads) {t.join();}cout << "Final counter value: " << counter << endl; // 应为 40000return 0;
}
构造函数
构造函数 | 说明 |
---|---|
explicit lock_guard(mutex_type& m); | 加锁并管理 m |
lock_guard(mutex_type& m, std::defer_lock_t); | 不加锁,仅管理(但 lock_guard 不支持 defer_lock)❌ |
lock_guard(mutex_type& m, std::adopt_lock_t); | 假设锁已由当前线程持有,仅接管 |
⚠️ 注意:std::lock_guard 不支持 std::defer_lock,它总是立即加锁。如果需要延迟加锁,请使用 std::unique_lock。
与 std::unique_lock 的对比
特性 | std::lock_guard | std::unique_lock |
---|---|---|
是否立即加锁 | 是 | 可延迟(defer_lock) |
是否可手动解锁 | 否 | 是(unlock()) |
是否支持条件变量 | 否 | 是 |
灵活性 | 低(简单场景) | 高(复杂场景) |
性能 | 更高(轻量) | 稍低(有状态) |
推荐场景 | 普通临界区保护 | 条件变量、复杂锁逻辑 |
优点总结
✅ 异常安全:即使临界区抛出异常,锁也会被释放
✅ 自动管理:无需手动调用 unlock()
✅ 代码简洁:避免忘记解锁
✅ 性能高:无额外开销
适用场景限制
❌ 不能用于需要尝试加锁(try_lock)的场景
❌ 不能用于需要条件变量(std::condition_variable)的场景
❌ 不能用于需要递归加锁的场景(除非使用 std::recursive_mutex)
总结
std::lock_guard 是 C++ 中最简单、最安全的互斥锁管理方式,应作为首选工具用于保护临界区。只要你的场景是“进入作用域加锁,离开作用域解锁”,就使用 std::lock_guard。
💡 记住一句话:“加锁后立即创建 lock_guard,让它帮你管理锁的生命周期。”
如果你需要更复杂的锁控制(如等待条件、手动解锁),再考虑使用 std::unique_lock。