Using mutex to fix Race Conditions

Using mutex to fix Race Conditions

本文主要讨论如何使用锁,以此保护多线程共享的数据,避免race conditions

std::mutex

c++11的线程库中,锁的使用在头文件<mutex>里。mutex有两个重要的方法:

  • lock()
  • unlock

接着上一篇文章,我们可以对wallet的变量进行锁保护,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
#include<thread>
#include<vector>
#include<mutex>

class Wallet
{
int mMoney;
std::mutex mutex;
public:
Wallet() :mMoney(0){}
int getMoney() { return mMoney; }
void addMoney(int money)
{
mutex.lock();
for(int i = 0; i < money; ++i)
{
mMoney++;
}
mutex.unlock();
}
};

在这种情况下,可能遇到的一个问题是,一个线程获取到锁之后,可能在释放锁之前就退出了。这种情况可能发生在上锁后出现异常退出。为了避免这种情况,我们应该使用std::lock_guard。

std::lock_guard

std::lock_guard是一个类模版,它实现了互斥锁的RAII。通过将锁包装在其对象中,并把互斥锁添加到构造函数中。当调用析构函数时,它就会释放互斥锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	
class Wallet
{
int mMoney;
std::mutex mutex;
public:
Wallet() :mMoney(0){}
int getMoney() { return mMoney; }
void addMoney(int money)
{
std::lock_guard<std::mutex> lockGuard(mutex);
// In constructor it locks the mutex

for(int i = 0; i < money; ++i)
{
// If some exception occurs at this
// poin then destructor of lockGuard
// will be called due to stack unwinding.
//
mMoney++;
}
// Once function exits, then destructor
// of lockGuard Object will be called.
// In destructor it unlocks the mutex.
}
};