互斥线程安全

当多个线程尝试访问资源时可能会出现问题。举一个简单的例子,假设我们有一个向变量添加一个的线程。它通过首先读取变量,向其中添加一个变量然后将其存储回来来完成此操作。假设我们将此变量初始化为 1,然后创建此线程的两个实例。两个线程完成后,直觉表明此变量的值应为 3.但是,下表说明了可能出错的地方:

线程 1 线程 2
时间步骤 1 从变量中读取 1
时间步骤 2 从变量中读取 1
时间步骤 3 加 1 加 1 得到 2
时间步骤 4 加 1 加 1 得到 2
时间步骤 5 将 2 存储到变量中
时间步骤 6 将 2 存储到变量中

如你所见,在操作结束时,2 位于变量中,而不是 3.原因是线程 2 在线程 1 完成更新之前读取变量。解决方案?互斥。

互斥体(mutman of mut ual ex clusion)是一个旨在解决此类问题的资源管理对象。当线程想要访问资源时,它获取资源的互斥锁。一旦完成访问资源,线程就释放互斥锁。获取互斥锁时,在释放互斥锁之前,所有获取互斥锁的调用都不会返回。为了更好地理解这一点,可以将互斥锁视为超市中的等待线:线程通过尝试获取互斥锁然后等待它们前面的线程完成,然后使用资源,然后走出释放互斥锁。如果每个人都试图立即访问资源,那么就会出现完全的混乱局面。

Version >= C++ 11

std::mutex 是 C++ 11 的互斥体实现。

#include <thread>
#include <mutex>
#include <iostream>
using namespace std;

void add_1(int& i, const mutex& m) { // function to be run in thread
    m.lock();
    i += 1;
    m.unlock();
}

int main() {
    int var = 1;
    mutex m;

    cout << var << endl; // prints 1
    
    thread t1(add_1, var, m); // create thread with arguments
    thread t2(add_1, var, m); // create another thread
    t1.join(); t2.join(); // wait for both threads to finish
    
    cout << var << endl; // prints 3
}