Когда следует использовать std:: atomic compare exchange strong?

В C++11 есть две атомарные операции CAS:atomic_compare_exchange_weak и atomic_compare_exchange_strong.

По данным cppreference:

слабые формы функций позволены потерпеть неудачу spuriously, то есть, действуйте как будто * obj != *ожидается, даже если они равны. Когда compare-and-exchange находится в цикле, слабая версия даст лучше производительность на некоторых платформах. когда слабый compare-and-exchange будет требуется петля и сильная нет, сильный предпочтительнее!--12-->.

пример использования слабый версия, мне кажется:

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

может ли кто-нибудь привести пример, когда сравнение и обмен не находятся в цикле, так что сильный версия предпочтительнее?

1 ответов


на atomic_compare_exchange_XXX функции обновляют свой" ожидаемый " аргумент с наблюдаемым значением, поэтому ваш цикл такой же, как:

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 является ненулевым идентификатором для текущего потока и current используется для обеспечения взаимного исключения, чтобы гарантировать, что некоторые поток выполняет задачу очистки. Нам все равно, какой из них, но мы хотим быть уверены, что какой-то поток получает доступ (и, возможно, другие потоки могут наблюдать за победителем, читая его 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";
}

это случай, когда 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 (§29.6.5/25 [Атомикс.типы.оперативный.запрос.)]