如何解决如何在C ++中使用原子防止关键部分访问
我有一个程序,其中有4个线程在两个“银行帐户”之间进行随机交易,每进行100次交易,每个帐户的利息为5%。
这是我必须要做的上学练习,在上一课中,我们使用了互斥锁,在锁定一段代码时看起来很简单。 现在我们必须做相同的事情,但要使用原子。
我的问题是,当前有多个线程可以进入addIntreset
函数,并且可以多次添加兴趣。
这是代码的一部分,我在其中检查是否是第100次交易
void transfer(Account& acc,int amount,string& thread)
{
++m_iCounter;
withdraw(acc,amount);
if (m_iCounter % 100 == 0)
{
addInterest(thread);
}
}
所有线程都通过该函数并检查%100,有时不止一个线程进入addInterest。使用互斥锁,我可以在此处限制访问权限,但是如何使用原子操作呢?
也许我可以在addInterest
内以某种方式解决此问题,但如果可以,如何解决?
addInterest
内是以下代码(如果多次添加超过1个感兴趣的线程滑动):
void addInterest(string& thread)
{
float old = m_iBalance.load();
const float interest = 0.05f;
const float amount = old * interest;
while (!m_iBalance.compare_exchange_weak(old,old + amount))
{
//
}
++m_iInterest;
cout << thread << " interest : Acc" << name << " " << m_iCounter << endl;
}
解决方法
一个问题是您分别递增和读取计数器,因此addInterest
可以被多次调用。要解决此问题,您应该自动编写和阅读。
const int newCounter = ++m_iCounter;
增加兴趣:
如果您添加兴趣并不重要,只要它在增加计数器后发生,那么您的addInterest
可能就可以了。
如果必须对第100个事务处理期间的余额增加利息(即使该线程到达addInterest
时已更改),则必须以某种方式存储旧余额,然后再增加计数器。我能想到的唯一方法是使用原子标志代替互斥体来同步整个transfer
:
// Member variable
std::atomic_bool flag;
// Before the critical section
bool expected;
do {
expected = false;
} while (!flag.compare_exchange_weak(expected,true));
// Critical section here
// Unlock at the end
flag = false;
,
确定2种可能的解决方案:
-
第一个是使用标头
atomic
中的<atomic>
模板,在这种情况下,您至少可以将m_iCounter
用作原子变量。但是为了获得更好的操作原子性,关键部分中的所有变量都必须是原子性的。 进一步阅读Atomic和Atomic template。 -
第二个选项是使用c ++的临时功能,即所谓的 STM (软件事务存储)。在这种情况下,
transfer
函数的所有内容都可以是事务,也可以是您之前已互斥的所有东西。 进一步阅读Transactional Memory c++
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。