c++ 何时应使用std::atomic_compare_exchange_strong?

w8f9ii69  于 2023-01-10  发布在  其他
关注(0)|答案(1)|浏览(185)

C++11中有两个原子CAS操作:atomic_compare_exchange_weakatomic_compare_exchange_strong
根据cppreference:
弱形式的函数允许错误地失败,也就是说,即使它们相等,也会表现为 * obj!=* expected。当比较和交换在循环中时,弱形式的函数在某些平台上会产生更好的性能。当弱比较和交换需要循环而强比较和交换不需要循环时,强比较和交换更可取
下面是一个使用 * weak * 版本的例子,我认为:

do {
    expected = current.value();
    desired = f(expected);
} while (!current.atomic_compare_exchange_weak(expected, desired));

有人能举一个例子,说明比较和交换不在循环中,所以 * strong * 版本更可取吗?

cuxqih21

cuxqih211#

atomic_compare_exchange_XXX函数用观察到的值更新它们的“expected”参数,因此您的循环如下所示:

expected = current;
do {
    desired = f(expected);
} while (!current.atomic_compare_exchange_weak(expected, desired));

如果期望值与期望值 * 无关 *,则该循环变为:

desired = ...;
expected = current;
while (current.atomic_compare_exchange_weak(expected, desired))
  ;

让我们添加一些语义。让我们假设有几个线程同时运行它。在每种情况下,desired都是当前线程的非零ID,而current用于提供互斥以确保某个线程执行清理任务。我们并不真正关心是哪个线程。但我们希望确保某个线程获得访问权(并且其他线程可能通过从current阅读优胜者的ID来观察赢家)。
我们可以通过以下方式实现所需的语义:

expected = 0;
if (current.atomic_compare_exchange_strong(expected, this_thread)) {
  // I'm the winner
  do_some_cleanup_thing();
  current = 0;
} else {
  std::cout << expected << " is the winner\n";
}

在这种情况下,atomic_compare_exchange_weak需要一个循环来实现与atomic_compare_exchange_strong相同的效果,因为可能出现伪故障:

expected = 0;
while(!current.atomic_compare_exchange_weak(expected, this_thread)
       && expected == 0))
  ;
if (expected == this_thread) {
  do_some_cleanup_thing();
  current = 0;
} else {
  std::cout << expected << " is the winner\n";
}

该标准建议,在这种情况下,实现可以为atomic_compare_exchange_strong提供比使用..._weak循环更高效的代码(atomics.types.operations/25)。

相关问题