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

Разница в mfence и asm volatile ( ":" memory")

Насколько я понял, mfence является аппаратным барьером памяти, а asm volatile ("" : : : "memory") является компилятором. Но вместо можно использовать asm volatile ("" : : : "memory").

Причина, по которой я запутался, - эта ссылка

4b9b3361

Ответ 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 от необходимости выдавать забор памяти.

В зависимости от платформы, на которой вы находитесь и что вы пытаетесь сделать, возможно, что-то "лучше" или более понятно... переносимость не выдерживает.

Ответ 2

  • asm volatile ("" ::: "memory") - это просто компилятор.
  • asm volatile ("mfence" ::: "memory") является и компилятором, и MFENCE
  • __sync_synchronize() также является барьером компилятора и полным барьером памяти.

поэтому asm volatile ("" ::: "memory") не будет препятствовать переупорядочению независимыми инструкциями данных CPU как таковым. Как указывалось, x86-84 имеет сильную модель памяти, но переупорядочение StoreLoad по-прежнему возможно. Если для работы вашего алгоритма необходим полный барьер памяти, вы можете выбрать __sync_synchronize

Ответ 3

Существует два переупорядочения: один - переупорядочение компилятора, другое - переупорядочение процессора.

x86/x64 имеет сильную модель памяти, но на x86/x64 может произойти переупорядочение BUSTLOW. см. http://en.wikipedia.org/wiki/Memory_ordering

  • asm volatile ("" ::: "memory") - это просто компилятор.
  • asm volatile ("mfence" ::: "memory") - это как барьер компилятора, так и процессорный барьер.

Это означает, что используйте только барьер компилятора, вы можете только предотвратить переупорядочение компилятора, но вы не можете предотвратить переупорядочение процессора. это означает, что при компиляции исходного кода не происходит переупорядочения, но переупорядочение может произойти во время выполнения.

Итак, это зависит от ваших потребностей, которые нужно использовать.