C++ 多线程同步实战:互斥锁与死锁规避
在多线程环境下,多个线程同时访问共享资源是常态,但这往往也是 Bug 的温床。当两个线程同时对同一个变量进行读写操作时,如果没有适当的保护机制,最终结果往往会偏离预期。这种问题被称为数据竞争,解决它的核心手段就是线程同步。
为什么需要互斥锁?
想象一下两个线程都在执行全局变量 count 的自增操作。看似简单的 count++,在底层其实包含了读取、修改、写回三个步骤。如果线程 A 读到值后还没写完,线程 B 也读到了旧值,那么其中一个增量就会丢失。
运行下面的代码片段,你会发现最终结果通常小于预期的累加次数:
#include <iostream>
#include <thread>
using namespace std;
int count = 0;
void increment() {
for (int i = 0; i < 100000; ++i) {
count++; // 非原子操作,存在数据竞争
}
}
int main() {
thread t1(increment);
thread t2(increment);
t1.join();
t2.join();
cout << "最终 count 值:" << count << endl;
return 0;
}
这就是典型的未同步场景。为了解决这个问题,我们需要引入互斥锁。
std::mutex 与 lock_guard 的正确用法
C++11 标准库中的 头文件提供了 std::mutex,这是最基础的互斥锁类型。它提供了 lock() 和 unlock() 接口,但手动管理锁的生命周期风险很大——一旦代码抛出异常,unlock() 可能无法执行,导致死锁。
因此,实际开发中更推荐配合 RAII 机制使用的 std::lock_guard。它在构造时自动加锁,析构时自动解锁,即使发生异常也能保证锁被释放。
改造上面的代码,加入互斥锁保护临界区:
#include
std;
count = ;
mutex mtx;
{
( i = ; i < ; ++i) {
;
count++;
}
}
{
;
;
t();
t();
cout << << count << endl;
;
}


