В 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));
Может ли кто-нибудь привести пример, когда сравнение и обмен не в цикле, так что сильный версия предпочтительнее?
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]).
Других решений пока нет …