对共享变量执行多个原子操作

Gou*_*ham 3 c++ concurrency boost boost-thread visual-c++

我想对共享变量进行两次操作。我需要保证它可以原子地完成。有人可以帮我澄清以下方法是否正确:

#include <atomic>
std::atomic<int> index;

void function()
{
     // I need the variable index to be incremented but bound in the 
     // range of [0,9].
     int loc_indx = index.load(std::memory_order_acquire);
     index.store( (loc_indx+1)%10  , std::memory_order_release);
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,索引存储操作和索引加载操作必须一起发生。这里的一些专家可以澄清上面的代码是否等同于以下伪代码:

ATOMIC
{
   index = (index+1)%10;
}
Run Code Online (Sandbox Code Playgroud)

我一直在 Visual Studio 2012 的 c++ 部分或/和 1.53 的 boost::atomic 部分中使用原子包。

Öö *_*iib 5

与锁相比,原子的全部目的是提高性能。

您的代码中没有锁。枚举memory_order只是为了确保编译器不会对代码进行重新排序(也不会让 CPU 对其进行重新排序)。load这意味着其他线程修改和之间的值的可能性很小store。如果存储的值必须依赖于先前的值,那么中间所做的计算就会被浪费,需要重做。这样做比锁的效率要高得多,因为并发修改实际发生的机会很低,而且计算成本低且简单。

当您知道以前的值时存储,否则重新计算并重试。就像是:

 int loc_index = index.load(std::memory_order_acquire);
 int desired = (loc_index+1)%10;

 while ( !index.compare_exchange_strong( loc_index, desired ) )
 {
     desired = (loc_index+1)%10;
 }
Run Code Online (Sandbox Code Playgroud)

compare_exchange_strongindex是原子操作,将存储在中的值进行比较loc_index;如果它们相等,则存储desiredindex; 如果它们不相等,则将 的值复制index到 中loc_index。这可以帮助您确保存储的下一个值index是正确的。

  • @goutham - (接上一条评论) - 本质上,它不断从“index”加载新值,增加其值,并将结果存储到“desired”中。然后它检查“index”中的值自上次加载以来是否已更改;如果不是,它将“desired”存储到“index”中并退出循环。另一方面,如果值发生变化,则其他线程在该线程工作的过程中进行了更新,因此它必须使用“index”的新值重试。 (2认同)