比较一些原子交换其他

时间:2015-05-14 11:28:52

标签: c++ c++11 atomic

今天我需要做的原子操作相当棘手,我需要一些帮助。简而言之,我想原子地执行以下操作:

/* begin of atomicity */
if (--counter == 0)
{
   Widget* widget = nullptr;

   swap(some_widget, widget);

   /* end of atomicity */

   // use local 'widget' here
}
/* end of atomicity */

我知道C ++ 11原子和内在函数。前面的代码只是,旨在显示我想要原子地发生的事情。我知道一个解决方案是让计数器有一个" Transition" state(例如0xFFFFFFFF)并且仅将其值更改为先转换到此转换,然后更改为新值:它基本上类似于自旋锁。关于如何有效地 的任何想法(即没有自旋锁,没有互斥,也可能没有等待)?

非常感谢。

1 个答案:

答案 0 :(得分:0)

假设C ++ 11,你想做一个原子fetch_and_add,然后使用结果。

例如:

std::atomic<int> counter = 20;

if (counter.fetch_sub(1) == 1) /* return value is old value */
{
   Widget* widget = nullptr;
   swap(some_widget, widget);
}

如果跨线程使用计数器,我们需要确保编译器和硬件不会弄乱内存排序。 std::atomic<>.fetch_sub()的默认排序是std::memory_order_seq_cst,这样做会很好,但如果你想获胜,例如ARM64,您可以减少到std::memory_order_acquire

为了使交换操作符合上述方案,我们需要一个锁。 有趣的是,这适合&#34;双重检查锁&#34;模式,这是一些人不赞成但在这里相当有用 - 对于大多数操作你不会受到锁定,但是当它重要时,它就在那里。 以下是:

std::atomic<int> counter = 20;
std::mutex  counterLock;
std::atomic<Widget*> some_widget;

...

if (counter.load(std::memory_order_acquire) > 5) /* first check whether we're "close enough" */
{
  /* only lock when needed */
  std::lock_guard<std::mutex> templock(counterLock); /* free lock whenever we exit this scope */
  if (counter.fetch_sub(1) == 1) /* return value is old value */
  {
    Widget* oldwidgetpr = some_widget.exchange(nullptr, std::memory_ordering_release);
    /* do whatever you need to do with the oldwidgetptr */
  }
}
else
  counter.fetch_sub(1);