主要解决多个线程在操作同一份共享数据时产生的线程安全问题

当某个表达式的求值写入某个内存位置,而另一求值读或修改同一内存位置时,称这些表达式冲突拥有两个冲突的求值的程序就有数据竞争,除非

  • 两个求值都在同一线程上,或者在同一信号处理函数中执行,或
  • 两个冲突的求值都是原子操作(见 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作用域之后解锁