Подтвердить что ты не робот

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);
}
4b9b3361

Ответ 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)