Ответ 1
Ну, барьер памяти необходим только для архитектур, имеющих слабый порядок памяти. x86 и x64 не имеют слабой памяти. на x86/x64 все магазины имеют заборный забор, и все нагрузки имеют забор. поэтому вам действительно нужно только asm volatile ("" : : : "memory")
Для получения хорошего обзора как Intel, так и AMD, а также ссылок на релевантные спецификации производителя см. http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/
Обычно такие вещи, как "volatile", используются для каждого поля, где нагрузки и хранилища в этом поле являются атомарными. Если нагрузки и хранилища в поле уже являются атомами (т.е. рассматриваемая операция является нагрузкой или хранилищем для одного поля и, следовательно, вся операция является атомарной), модификатор поля volatile
или барьеры памяти не нужны на x86/x64. Несмотря на переносимый код.
Когда дело доходит до "операций", которые не являются атомарными - например. загружает или сохраняет в поле, которое больше, чем собственное слово, или загружает или сохраняет в несколько полей в рамках "операции" - средство, с помощью которого операция может рассматриваться как атомарная, требуется независимо от архитектуры ЦП. обычно это делается с помощью примитива синхронизации, такого как мьютекс. Мьютексы (те, которые я использовал) включают в себя барьеры памяти, чтобы избежать проблем, таких как переупорядочение процессора, поэтому вам не нужно добавлять дополнительные инструкции по защите памяти. Я вообще не считаю использование примитивов синхронизации преждевременной оптимизацией; но природа преждевременной оптимизации, конечно же, составляет 97% времени:)
Если вы не используете примитив синхронизации и имеете дело с многополюсным инвариантом, важны барьеры памяти, которые гарантируют, что процессор не переупорядочивает магазины и нагрузки в разных местах памяти.
Теперь, с точки зрения не выдачи инструкции "mfence" в asm volatile, но используя "память" в списке clobber. Из того, что мне удалось читать
Если ваши инструкции ассемблера непреднамеренно попадают в память, добавьте "память" в список скребковых регистров. Это приведет к тому, что GCC не сохранит значения памяти, хранящиеся в кэшах в регистре, в инструкции ассемблера, а не оптимизирует хранилища или нагрузки в эту память.
Когда они говорят "GCC" и ничего не говорят о CPU, это означает, что он применяется только к компилятору. Отсутствие "mfence" означает отсутствие защитного барьера ЦП. Вы можете проверить это, разобрав полученный двоичный файл. Если инструкция "mfence" не выдается (в зависимости от целевой платформы), тогда она очищает CPU от необходимости выдавать забор памяти.
В зависимости от платформы, на которой вы находитесь и что вы пытаетесь сделать, возможно, что-то "лучше" или более понятно... переносимость не выдерживает.