什么时候应该使用std :: atomic_compare_exchange_strong?

use*_*470 9 c++ multithreading atomic compare-and-swap c++11

C++ 11中有两个原子CAS操作:atomic_compare_exchange_weakatomic_compare_exchange_strong.

根据cppreference:

允许函数的弱形式虚假地失败,即,即使它们是相等的,也可以表现为*obj!=*.当比较和交换处于循环中时,弱版本将在某些平台上产生更好的性能.当一个弱的比较和交换需要一个循环而一个强大的那个不需要时,强者更可取.

以下是使用版本的示例,我认为:

do {
    expected = current.value();
    desired = f(expected);
} while (!current.atomic_compare_exchange_weak(expected, desired));
Run Code Online (Sandbox Code Playgroud)

有人可以给出比较和交换不在循环中的示例,以便版本更可取吗?

Cas*_*sey 9

atomic_compare_exchange_XXX功能与观测值更新他们的"预期"的说法,所以你的循环是一样的:

expected = current;
do {
    desired = f(expected);
} while (!current.atomic_compare_exchange_weak(expected, desired));
Run Code Online (Sandbox Code Playgroud)

如果所需的值与预期值无关,则此循环变为:

desired = ...;
expected = current;
while (current.atomic_compare_exchange_weak(expected, desired))
  ;
Run Code Online (Sandbox Code Playgroud)

让我们添加一些语义.假设有几个线程同时运行它.在每种情况下desired,当前线程current都是非零ID,用于提供互斥以确保某些线程执行清理任务.我们并不关心哪一个,但我们想确保一些线程可以访问(也许其他线程可以通过读取它的ID来观察获胜者current).

我们可以通过以下方式实现所需的语义:

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";
}
Run Code Online (Sandbox Code Playgroud)

这种情况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";
}
Run Code Online (Sandbox Code Playgroud)

该标准表明,在这种情况下,实现可以提供atomic_compare_exchange_strong比使用..._weak(§29.6.5/ 25 [atomics.types.operations.req])循环更有效的代码.