std::lock_guard不可拷贝仅可栈上构造,因其遵循RAII独占所有权原则:构造时加锁、析构时自动解锁;若允许拷贝,会导致多个对象析构时重复解锁同一把锁,引发未定义行为。

std::lock_guard 为什么不能拷贝只能移动?
因为 std::lock_guard 的设计目标是「RAII + 独占持有」:它在构造时加锁,析构时自动解锁。如果允许拷贝,两个对象会同时指向同一把锁,析构时就会重复解锁——轻则 std::terminate,重则 UB(未定义行为)。
所以它的拷贝构造函数和拷贝赋值运算符都被显式删除了(= delete)。你写 auto guard2 = guard1; 会直接编译失败,报错类似:use of deleted function 'std::lock_guard<:mutex>::lock_guard(const std::lock_guard<:mutex>&)'。
实操建议:
- 永远用栈变量声明,比如
std::lock_guard<:mutex> guard(mtx); - 不要尝试传值返回或存入容器;若需转移语义,改用
std::unique_lock(它支持移动) - 想“延长”作用域?靠代码块控制,而不是复制对象
std::lock_guard 构造时就加锁,那怎么避免死锁?
它确实会在构造函数里调用 mtx.lock(),这意味着一旦构造失败(比如锁已被占用且不可重入),线程就会阻塞等待。这不是「避免死锁」,而是「可能陷入死锁」——尤其当你按不同顺序对多个互斥量加锁时。
常见错误现象:线程 A 持有 mtx1 并等待 mtx2,线程 B 持有 mtx2 并等待 mtx1,双双卡住。
正确做法是统一加锁顺序,或使用 std::scoped_lock(C++17 起):
std::mutex mtx1, mtx2; // ✅ 推荐:一次性加多把锁,自动规避死锁 std::scoped_lock lock(mtx1, mtx2); // ❌ 危险:顺序不一致极易引发死锁 std::lock_guard g1(mtx1); std::lock_guard g2(mtx2); // 如果另一处写成 g2 先、g1 后,就埋雷了
注意:std::scoped_lock 是 std::lock_guard 的安全替代品,支持多锁且无死锁风险;而 std::lock_guard 只适合单锁场景。
std::lock_guard 能用在 if 或循环里吗?
能,而且这是它最典型的用法——靠作用域精确控制临界区范围。很多人误以为必须包整个函数,其实越细粒度越好。
使用场景举例:只保护某次 map 查找+插入,而不是整个处理逻辑。
实操建议:
- 把
std::lock_guard声明放在尽可能靠近需要保护的数据操作的位置 - 用大括号显式划界,比如
{ std::lock_guard g(mtx); shared_data.push_back(x); } - 别把它和条件逻辑耦合太紧,例如避免
if (cond) std::lock_guard g(mtx);—— 这样 g 会立即析构,起不到保护作用
错误写法示例:
if (need_update) {
std::lock_guard g(mtx); // ✅ 加锁
data = new_value; // ✅ 临界区
} // ✅ 析构在这里发生,及时释放
// ✅ 正确
if (need_update)
std::lock_guard g(mtx); // ❌ 作用域仅到分号,立刻析构
data = new_value; // ❌ 此时已无锁保护!
std::lock_guard 和 std::unique_lock 该怎么选?
核心区别就一条:是否需要「延迟加锁」「手动解锁」「转移所有权」。如果不需要,就用 std::lock_guard;否则必须换 std::unique_lock。
性能影响:两者构造/析构开销基本一致,但 std::unique_lock 对象更大(含额外状态位),且每次调用 unlock() / lock() 都有轻微运行时开销。
参数差异:
-
std::lock_guard只接受一个mutex类型参数(可带std::defer_lock_t标签,但没意义——它不支持延迟) -
std::unique_lock支持std::defer_lock、std::try_to_lock、std::adopt_lock等策略 - 只有
std::unique_lock能传给std::condition_variable::wait()
一句话判断:你写 g.unlock() 了吗?写了,就必须是 std::unique_lock。
实际项目里最容易被忽略的点是:以为 std::lock_guard 能解决所有同步问题,结果在需要条件等待或分段加锁时硬套它,最后要么编译不过,要么逻辑出错。它只是最简 RAII 封装,不是万能锁管理器。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











