3

例如,您可以安全地递增和递减 std::atomic_int。但是,如果您需要检查溢出或根据值有条件地执行一些例程,那么无论如何都需要锁定。由于您必须比较该值,并且线程可能在比较成功后立即被交换,另一个线程修改,......错误。

但是如果你需要一个锁,那么你可以只使用一个普通的整数而不是原子的。我对吗?

4

1 回答 1

3

不,您仍然可以有条件地使用 std::atomic 。

首先,如果您使用,std::atomic<unsigned int>则溢出行为是明确定义的(尽管可能不是您想要的)。如果您使用带符号整数溢出的定义不明确,但只要您不点击它,那么这无关紧要。

如果你绝对必须检查溢出,或者有条件地采取行动,你可以使用 compare-exchange。这使您可以读取该值,决定是否要对其进行处理,然后如果该值未更改,则以原子方式更新该值。而这里的关键部分是系统会告诉你原子更新是否失败,在这种情况下,你可以回到开始并读取新值并再次做出决定。

例如,如果我们只想将原子整数的最大值设置为 4(例如,在某种引用计数中),我们可以这样做:

#include <atomic>

static std::atomic<int> refcount = 0;

int val = refcount; // this doesn't need to be in the loop as on failure compare-exchange-strong updates it
while(true)
{
   if(val == 4)
   {
       // there's already 4 refs here, maybe come back later?
       break;
   }

   int toChangeTo = val + 1;
   if(refcount.compare_exchange_strong(val, toChangeTo))
   {
       // we successfully took a ref!
       break;
   }

    // if we fail here, another thread updated the value whilst we were running, just loop back and try again
}

在上面的代码中,您可以compare_exchange_weak改用。这有时会虚假地失败,因此您需要循环执行。但是,无论如何,我们都有一个循环(通常你总是会因为你需要处理真正的故障),所以compare_exchange_weak在这里很有意义。

于 2013-06-01T08:38:03.397 回答