浅谈c多线程中的资源竞争

在这篇文章中,我们将讨论如何使用mutexlocks来阻止共享数据在多线程环境下的资源竞争问题

什么是资源竞争(racecondition)

Racecondition是一种多线程中的bug。

当进程中的多个线程,同时读取一块内存数据,与此同时其中一个或多个线程修改了这块内存数据。这样就会导致不可预期的结果

因为线程不安全引起的错误往往非常难发现,因为这种现象是不能稳定复现的。

让我们来看一下这种现象

图1钱包类

如图1,我们首先定义了一个钱包类,然后我们创建五个线程,这五个线程同时来操作这个钱包,给其增加元钱。

图2创建5个线程,操作这个钱包

我们期待的是最终程序结束后,钱包里的金额应该为。循环次,结果都不尽然。

Outputis,

Erroratcount=MoneyinWallet=

Erroratcount=MoneyinWallet=

Erroratcount=MoneyinWallet=

Erroratcount=MoneyinWallet=

Erroratcount=MoneyinWallet=

Erroratcount=MoneyinWallet=

发生了什么

图1中,代码11行,并不是原子操作,其实这一行代码分为三步:

将mMoney变量放到寄存器将寄存器中的值+1将寄存器的值赋给mMoney

所以在执行中,经常会出现这种情况

图3错误的根源

解决方案:锁

mutex称之为锁。每个线程在读写一个共享变量的时候,需要先对变量进行加锁操作,完成后,再将锁拿掉。

这两个动作,我们分别称之为lockmutex和unlockmutex。

在C++11中,mutexs使用mutex头文件引入,使用最多的是std::mutex类,这个类有两个重要的方法

1)lock()

2)unlock()

首先,我们将钱包类修改为图4,我们在图4的15行增加了mutex,这样再执行图2的代码,程序结束后,钱包内的金额即为元

图4

更高级的用法

图4中,我们可以看到,mutex的lock()和unlock是配对的。如果我们只使用了lock,之后忘记unlock。在这种情况下,一个线程将永远保持对这个变量的使用权,其他线程将永远处于等待状态

为了防止这种问题的发生。c++11引入了std::lock_guard。在lock_gurad创建的时候开始加锁,在其析构的时候,释放锁。具体用法,见图5

图5


转载请注明:http://www.aierlanlan.com/rzdk/3400.html