c++ - 如何在C++中使用原子防止关键部分访问

标签 c++ multithreading atomicity

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

关于c++ - 如何在C++中使用原子防止关键部分访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64277401/

相关文章:

c++ - 给 long long c++ 赋值时应该使用 LL

c++ - 构造函数中的模板冲突

arrays - 计算数组平均值的高效并行调度算法

java - 等待线程永远不会醒来

multithreading - 发出信号量必须是原子的。 Pintos的sema_down安全吗?

java - volatile 和原子之间的区别

C++ SFML Sprite 位置在函数中不更新

c++ - 为什么这不是一个常量表达式?

r - 在R中如何控制BLAS并行矩阵乘积中的多线程