X86: Нужны ли здесь барьеры памяти?

Kay спросил: 28 марта 2018 в 01:56 в: x86

В WB-памяти a = b = 0

P1:
a = 1
SFENCE
b = 1P2:
WHILE (b == 0) {}
LFENCE
ASSERT (a == 0)

Я понимаю, что ни SFENCE, ни LFENCE.

А именно, поскольку для этого типа памяти x86 обеспечивает:

  1. Считывание не может быть переупорядочено с помощью более старых чтений
  2. Магазины не могут быть переупорядочены со старыми хранилищами.
  3. Магазины транзитивно видны

1 ответ

Есть решение
Peter Cordes ответил: 28 марта 2018 в 10:26

Инструкции asm lfence и sfence не допускаются, если вы не используете хранилища NT (или NT загружается из памяти WC, например, видеопамяти). (На самом деле, movntdqa загрузки могут быть заказаны только mfence на бумаге , а не lfence. В этом случае Я не знаю, когда вы когда-нибудь использовали lfence. Он был добавлен в ISA вместе с sfence + mfence одновременно с хранилищами NT, до movntdqa, возможно, просто для полноты / на случай, если это когда-либо понадобилось.)

Иногда возникает путаница вокруг этой точки, потому что внутренняя часть C / C ++ для lfence и sfence также являются барьерами компилятора. Это необходимо в C / C ++, но его можно получить дешевле с помощью GNU C asm("":::"memory"); или (чтобы упорядочить операции atomic 1 ) std::atomic_signal_fence(std::memory_order_acq_rel). Ограничивает переупорядочение времени компиляции , не заставляя компилятор выдавать любые бесполезные инструкции asm-барьера.


Переупорядочение во время выполнения уже заблокировано моделью памяти x86, за исключением переупорядочения StoreLoad, для которого требуется mfence. lfence + sfence не суммировать с mfence. См. Имеет ли смысл инструкция LFENCE для процессоров x86 / x86_64? и другие различные SO Q & Как насчет этих инструкций.

Вот почему std::atomic_thread_fence(std::memory_order_acq_rel) также компилирует нулевые инструкции на x86, но с барьерами на слабо упорядоченных архитектурах.


lfence также является инструкцией сериализации на микроархитектурах Intel (но, возможно, нет AMD?). Это было все время, но Intel недавно сделала эту гарантию официальной, чтобы методы смягчения воздействия Spectre могли безопасно использовать ее вместо гораздо более неудобного cpuid.


  • Сноска 1

atomic_signal_fence в gcc также может быть барьером компилятора для простых не atomic переменных; это был последний раз, когда я проверял с помощью gcc (в то время как atomic_thread_fence этого не было), но это, вероятно, просто деталь реализации, когда не задействованы переменные atomic. Когда есть переменные atomic, компилятор знает, что эти переменные могут обеспечивать порядок, позволяющий другим потокам обращаться к неатомарным переменным без UB, поэтому порядок необходим.

Kay ответил: 28 марта 2018 в 05:17
Привет, Питер, спасибо за ответ. Что касается вашего комментария, то да, это псевдокод сборки, поэтому компиляторные барьеры не нужны. Отлично - я рада, что у меня все получается. Как всегда, спасибо за ваше время.