我有一个程序,其中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;

09-06 17:01