std::mutex 必须配合 std::lock_guard 或 std::unique_lock 使用,不可裸调 lock()/unlock(),因其不支持拷贝、需 RAII 管理生命周期,且裸用易致死锁或资源泄漏。

直接说结论:std::mutex 本身不能“使用”,只能“配合 std::lock_guard 或 std::unique_lock 使用”,否则极易死锁或忘记解锁。
为什么不能直接调用 lock() / unlock()
裸调 mutex.lock() 和 mutex.unlock() 是危险操作:异常抛出、提前 return、逻辑分支遗漏都会导致 unlock() 被跳过,锁永远不释放——后续线程卡死。
正确做法是依赖 RAII 自动管理生命周期:
-
std::lock_guard<:mutex>:最常用,构造即加锁,析构即解锁,不可转移,轻量 -
std::unique_lock<:mutex>:更灵活(可延迟加锁、手动解锁、转移所有权),但有轻微开销
示例:
立即学习“C++免费学习笔记(深入)”;
std::mutex mtx;
int shared_data = 0;
void increment() {
std::lock_guard lock(mtx); // 构造时自动 lock()
++shared_data; // 临界区
} // 离开作用域,lock 析构,自动 unlock()
std::mutex 不能复制,只能移动(且通常不移动)
std::mutex 删除了拷贝构造和拷贝赋值,编译器会报错如:use of deleted function ‘std::mutex::mutex(const std::mutex&)’。
这意味着:
- 不能放进
std::vector<:mutex>(因 vector 可能 realloc 并尝试拷贝) - 不能作为类成员被默认拷贝(需显式禁用拷贝或定义移动语义)
- 若需多个互斥量,用
std::array<:mutex n>或std::vector<:unique_ptr>>
常见误用:在 lambda 捕获中传 std::mutex 对象本身
错误写法:
std::mutex mtx;
std::thread t([mtx]() { // ❌ 拷贝 mtx → 编译失败
mtx.lock();
});
正确方式只有两种:
- 按引用捕获:
[&mtx](注意确保mtx生命周期长于线程) - 用
std::ref(mtx)包装后值捕获:[m = std::ref(mtx)]
更安全的惯用法是把锁逻辑封装进函数对象内部,避免裸 mutex 外泄。
性能与替代方案:std::mutex 不是万能解药
std::mutex 是重量级同步原语,争抢激烈时可能引发线程挂起/唤醒开销,甚至伪共享(false sharing)问题。
考虑这些替代:
- 无锁设计:用
std::atomic替代简单计数器 - 分片锁(sharding):把一个大 map 拆成多个子 map + 对应 mutex,降低争抢
-
std::shared_mutex(C++17):读多写少场景下提升并发读性能
记住:加锁范围越小越好,临界区里只放真正共享访问的代码;std::mutex 解决的是“怎么安全地改”,不是“要不要改”。











