互斥线程安全
当多个线程尝试访问资源时可能会出现问题。举一个简单的例子,假设我们有一个向变量添加一个的线程。它通过首先读取变量,向其中添加一个变量然后将其存储回来来完成此操作。假设我们将此变量初始化为 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
}