【问题标题】:Doing more than one atomic operations on shared variable对共享变量执行多个原子操作
【发布时间】:2013-02-13 17:05:23
【问题描述】:

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

#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);
}

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

ATOMIC
{
   index = (index+1)%10;
}

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

【问题讨论】:

  • 是否所有线程都通过调用function()来访问index?还是他们可以随意访问index
  • 增量只能通过所有线程调用function()来完成。是的,有更多线程同时访问function()

标签: c++ visual-c++ boost concurrency boost-thread


【解决方案1】:

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

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

当你知道之前的值时存储,否则重新计算并重试。比如:

 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;
 }

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

【讨论】:

  • 第 4 行缺少((从 1:-) 开始)。
  • 如果您可以添加一些解释,那将非常有帮助。
  • @goutham - 对compare_exchange_strong 的调用将index 中存储的值与loc_index 进行比较;如果它们相等,它将desired 存储到index;如果它们不相等,它会将index 的值复制到loc_index。所有这些都是原子完成的。在第一种情况下它返回真,在第二种情况下它返回假。很浓,不是吗? &lt;g&gt;。 (空间不足;请参阅下一条评论)
  • @goutham -(接上一条评论)-本质上,它不断地从index 加载一个新值,增加它的值,并将结果存储到desired。然后它检查index 中的值自上次加载以来是否发生了变化;如果不是,它将desired 存储到index 中并退出循环。另一方面,如果值改变了,那么其他线程在这个线程工作的中间进行了更新,所以它必须重试,使用index的新值。
  • @jogojapan 好主意!我添加了一些文字来讨论背景。希望它能解释为什么 OP 代码过于幼稚。
猜你喜欢
  • 2021-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多