如何比较和增加原子变量

时间:2017-12-11 12:57:43

标签: multithreading c++11

我想知道是否可以使用单个原子操作执行原子变量的比较和增量。这是我到目前为止所写的内容(线程的代码片段)

std::atomic<int> counter; //global variable

if(counter<25)
{
counter++;
}
else
{
     //send serial/socket data
}

我知道我做错了,因为原子变量计数器被访问了两次(一次用于获取数据,另一次用于增量)。但是,如果另一个线程在获取变量值之后和增量之前对'counter'执行某些更新操作,这可能会导致问题。所以我想知道是否可以一次性完成这两项操作。我也不想使用互斥锁。

2 个答案:

答案 0 :(得分:1)

if(counter<25) counter++;中,在读取计数器和更新计数器之间存在竞争条件(即原子加载后跟原子加载 - 修改 - 存储)。

它需要一个比较交换循环来确保读取的值从那时起没有改变。如果已更改,则需要重试该操作。

如下所示:

std::atomic<int> counter;

auto value = counter.load(std::memory_order_relaxed);
while(value < 25) {
    if(counter.compare_exchange_weak(value, value + 1, std::memory_order_release, std::memory_order_relaxed))
        break; // Succeeded incrementing counter.
    // compare_exchange_weak failed because counter has changed.
    // compare_exchange_weak reloaded value with the new value of counter.
    // Retry.
}
if(!(value < 25))
    // Failed to increment because counter is not less than 25.

答案 1 :(得分:-1)

更接近的代码可能是“类似”:

const int GUARD = 25;
auto value = counter.load()
if (value < GUARD)
{

    auto expectValue = value;
    auto newValue = expectValue + 1;
    for(;;)
    {
        if (counter.cmpxchg(expect,new))
        {    
             break;  // we did it!
        }
        newValue = expectValue + 1; 
        if (expectValue >= GUARD)
        {    
             break; // someone else did it!
        }
        // someone else incremented, now we increment again
        // cmpxchg updates expected with the new value
    }
    if (newValue <= GUARD)
    {
         // do the work you only want to do 25 times.
    }
}