Когда следует использовать std :: atomic_compare_exchange_strong?

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

В соответствии с cppreference:

Слабые формы функций допускаются случайным образом, что
действует, как будто * obj! = * ожидается, даже если они равны. Когда
сравнение и обмен в цикле, слабая версия даст лучше
производительность на некоторых платформах. Когда слабое сравнение и обмен
требуется петля, а сильная — нет, сильная
предпочтительный
.

Ниже приведен пример использования слабый версия, я думаю:

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

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

9

Решение

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 используется для обеспечения взаимного исключения, чтобы гарантировать, что некоторый поток выполняет задачу очистки. Нам не важно, какой из них, но мы хотим быть уверены, что какой-то поток получит доступ (и, возможно, другие потоки могут наблюдать за победителем, считывая его идентификатор из 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 [atomics.types.operations.req]).

9

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]