Std:: atomic | compare_exchange_weak против compare_exchange_strong
Я до сих пор не уверен, что это я не понимаю, или документация четко сформулирована.
Следующий отрывок был взят из новейшего проекта (N3126, раздел 29.6):
bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired);
bool atomic_compare_exchange_weak(A* object, C * expected, C desired);
bool atomic_compare_exchange_strong(volatile A* object, C * expected, C desired);
bool atomic_compare_exchange_strong(A* object, C * expected, C desired);
bool atomic_compare_exchange_weak_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_weak_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_strong_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_strong_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure);
bool A::compare_exchange_weak(C & expected, C desired, memory_order success, memory_order failure) volatile;
bool A::compare_exchange_weak(C & expected, C desired, memory_order success, memory_order failure);
bool A::compare_exchange_strong(C & expected, C desired, memory_order success, memory_order failure) volatile;
bool A::compare_exchange_strong(C & expected, C desired, memory_order success, memory_order failure);
bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile;
bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst);
bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile;
bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst);
Примечание: слабый сравнительный обмен операции могут ошибочно, что, возвращает false, оставляя содержимое памяти, на которое указывает ожидаемый до операции то же самое, что и у объекта и то же, что и ожидаемое после операция. [Примечание: этот поддельный сбой позволяет реализовать сравнение и обмен по более широкому класс машин, например, без нагрузки складско-условные машины. следствием ложного отказа является что почти все виды использования слабых сравнение и обмен будут в цикл.
Итак, что это значит? Во-первых, это может "не так" ложно?! Почему это происходит? И как они определяют "может"? Во-вторых, я не знаю почему, но я до сих пор не знаю, какая разница между функциями с суффиксами "_strong" и "_weak".
Надеюсь, кто-нибудь может помочь;)
С наилучшими пожеланиями.
EDIT:
Это то, что я нашел в libstdС++ - реализация (atomic_0.h):
bool compare_exchange_weak(
__integral_type& __i1,
__integral_type __i2,
memory_order __m1,
memory_order __m2
)
{
__glibcxx_assert(__m2 != memory_order_release);
__glibcxx_assert(__m2 != memory_order_acq_rel);
__glibcxx_assert(__m2 <= __m1);
return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
}
bool compare_exchange_strong(
__integral_type& __i1,
__integral_type __i2,
memory_order __m1,
memory_order __m2
)
{
__glibcxx_assert(__m2 != memory_order_release);
__glibcxx_assert(__m2 != memory_order_acq_rel);
__glibcxx_assert(__m2 <= __m1);
return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
}
Ответы
Ответ 1
Это связано с моделью согласованности общей памяти, которую реализует аппаратное обеспечение. Для тех аппаратных архитектур, которые реализуют какую-то непринужденную модель согласованности (например, семантику выпуска), сильные операции, о которых вы говорите выше, могут иметь высокие накладные расходы, и поэтому эксперты могут использовать более слабые формы для реализации алгоритмов, которые хорошо работают и на такой непринужденной консистенции архитектуры.
Для получения дополнительной информации см., например,
http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-7.pdf
Глава 12 и Приложение C в http://kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html
Ответ 2
Примечание дает ключ, ссылаясь на LL/SC. Из статьи в Википедии:
Если произошли какие-либо обновления, гарантируется сбой в состоянии хранилища, даже если значение, прочитанное ссылкой на загрузку, было восстановлено. Таким образом, пара LL/SC сильнее, чем чтение, за которым следует сравнение и своп (CAS), которая не будет обнаруживать обновления, если старое значение было восстановлено (см. Проблему ABA).
Реальные реализации LL/SC не всегда успешны, если нет параллельных обновлений в рассматриваемой ячейке памяти. Любые исключительные события между двумя операциями, такие как контекстный переключатель, другая ссылка на загрузку или даже (на многих платформах) другая операция загрузки или хранения, приведут к ложному отказу в состоянии хранилища.
В чипах LL/SC compare_exchange
будет реализован в терминах LL/SC, которые могут ложно терпеть неудачу, поэтому compare_exchange_strong
требует дополнительных накладных расходов, чтобы повторить попытку в случае сбоя. Предоставление как compare_exchange_strong
, так и compare_exchange_weak
позволяет программисту решить, хотят ли они, чтобы библиотека обрабатывала ложные сбои (в этом случае они использовали бы compare_exchange_strong
или если они хотят обрабатывать ее в своем собственном коде (в этом случае они 'd use compare_exchange_weak
)