@ the8472 ответ правильный, но я хотел добавить альтернативный ответ.
https://www.felixcloutier.com/x86/CMPXCHG.html уже определяет поведение достаточно подробно, чтобы исключить возможность ложного сбоя. Если это может произойти сбой по какой-либо причине, кроме значения в памяти, не совпадающего с eax
, документы должны будут сказать об этом.
Также можно отметить тот факт, что компиляторы используют один lock cmpxchg
для C ++ 11 std::atomic::compare_exchange_strong
, из чего можно сделать вывод, что авторы компилятора считают, что lock cmpxchg
не может внезапно потерпеть неудачу.
#include <atomic>
bool cas_bool(std::atomic_int *a, int expect, int want) {
return a->compare_exchange_strong(expect, want);
}
компилируется в (gcc7.3 -O3) :
cas_bool(std::atomic<int>*, int, int):
mov eax, esi
lock cmpxchg DWORD PTR [rdi], edx
sete al
ret
См. Также Может ли num ++ быть атомарным для 'int num'? для более подробной информации о том, как lock
редактируемые инструкции реализованы внутри, и как они взаимодействуют с MESI. (т. е. @ the8472 - это короткая версия: для операнда, который не пересекает строку кэша, ядро просто висит на этой строке кэша, так что ничто другое в системе не может прочитать или записать его в течение lock cmpxchg
** 1027).
целевой операнд получает цикл записи без учета результата сравнения
Пара read + write является атомарной по отношению ко всем другим наблюдателям в системе. Порядок, который вы предлагаете, для read1 / read2 / write1 / abort write2 невозможен, потому что lock cmpxchg
является атомарным, поэтому read2
не может появляться между read1 и write1 в глобальном порядке.
Кроме того, этот язык применяется только к шине внешней памяти. Современные процессоры со встроенными контроллерами памяти могут делать все, что угодно (за lock cmpxchg
по адресу, разделенному на две строки кэша). Корпорация Intel может публиковать документацию для поставщиков материнских плат для использования при внутреннем тестировании сигналов на шине памяти.
Эта документация может все еще иметь отношение к lock cmpxchg
для адреса MMIO, но определенно не для выровненного операнда в памяти обратной записи. В этом случае это просто блокировка кеша. (И это скрытая деталь реализации, независимо от того, записан ли кеш L1d или нет при сбое сравнения). Я думаю, вы могли бы проверить это, посмотрев, не загрязняет ли она строку кэша (то есть переводит ли она в измененное состояние вместо исключительного).
Для получения дополнительной информации о том, как lock cmpxchg
может работать внутренне против xchg
, см. Ветку чата между мной и @BeeOnRope после моего ответа на Выход из критической области . (В основном, у меня есть идеи, которые могут работать теоретически, но несовместимы с тем, что мы знаем о процессорах Intel x86, и @BeeOnRope указывает на мои ошибки. https://chat.stackoverflow.com/transcript/message/42472667#42472667. Мы очень мало можем точно сказать о мелких деталях эффективность xchg
против lock cmpxchg
. Конечно, возможно, что xchg
удерживает строку кэша на меньшее количество циклов, чем lock cmpxchg
, но это необходимо проверить. Я думаю, что xchg
имеет большую задержку, если используется обратно. Впрочем, в одном и том же месте из одного потока.)