主要解决多个线程在操作同一份共享数据时产生的线程安全问题
当某个表达式的求值写入某个内存位置,而另一求值读或修改同一内存位置时,称这些表达式冲突。拥有两个冲突的求值的程序就有数据竞争,除非
- 两个求值都在同一线程上,或者在同一信号处理函数中执行,或
- 两个冲突的求值都是原子操作(见
std::atomic
),或 - 一个冲突的求值发生早于 另一个(见
std::memory_order
) 下面介绍解决竞争导致的线程安全问题的方法
使用互斥量
std::mutex
std::mutex
为互斥锁,可以用于保护共享数据,解决线程安全问题,使用举例如下:
#include<iostream>
#include<thread>
#include<mutex>
#include<vector>
using namespace std;
mutex m;
int main() {
auto f = [](int i) {
m.lock();
cout << "thread: " << this_thread::get_id() << " get: " << i << endl;
m.unlock();
};
vector<thread> threads;
for(int i = 0 ; i < 10 ; i ++) {
threads.emplace_back(f , i);
}
for(auto& t : threads) {
if(t.joinable()) {
t.join();
}
}
}
std::lock_guard
- 使用了
RAII
思想,把互斥锁的解锁和对象的析构函数联系起来了 - 拥有两个构造函数:
explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) {
_MyMutex.lock();
}
lock_guard(_Mutex& _Mtx, adopt_lock_t) noexcept: _MyMutex(_Mtx) {} // construct but don't lock
- 上面一个构造函数在管理互斥锁之后会上锁,如果原来的互斥锁上锁了,就会形成死锁,后面一个需要提前上锁,离开
lock_guard
作用域之后解锁