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

С++ Memory Barriers для Atomics

Я новичок, когда дело доходит до этого. Может ли кто-нибудь дать упрощенное объяснение различий между следующими барьерами памяти?

  • Окна MemoryBarrier();
  • Забор _mm_mfence();
  • Встроенная сборка asm volatile ("" : : : "memory");
  • Внутренний _ReadWriteBarrier();

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

4b9b3361

Ответ 1

Оба MemoryBarrier (MSVC) и _mm_mfence (поддерживаемые несколькими компиляторами) обеспечивают ограждение аппаратной памяти, что препятствует переходу процессора на чтение и запись через забор.

Основное различие заключается в том, что MemoryBarrier имеет специфичные для платформы реализации для x86, x64 и IA64, где в качестве _mm_mfence специально используется команда mfence SSE2, поэтому она не всегда доступна.

В x86 и x64 MemoryBarrier реализованы с xchg и lock or соответственно, и я видел некоторые утверждения о том, что это быстрее, чем mfence. Однако мои собственные тесты показывают противоположное, поэтому, по-видимому, он очень сильно зависит от модели процессора.

Другое отличие заключается в том, что mfence также может использоваться для упорядочения невременных хранилищ/нагрузок (movntq и т.д.).

GCC также имеет __sync_synchronize, который генерирует аппаратный забор.

asm volatile ("" : : : "memory") в GCC и _ReadWriteBarrier в MSVC обеспечивают только ограждение памяти уровня компилятора, не позволяя компилятору переупорядочивать доступ к памяти. Это означает, что процессор по-прежнему свободен для переупорядочения.

Запонки компилятора обычно используются в сочетании с операциями, которые имеют своего рода неявный аппаратный забор. Например. на x86/x64 все магазины имеют заборный забор, а нагрузка имеет забор, поэтому вам нужно только ограждение компилятора при реализации load-purchase и store-release.

Ответ 2

См. мой ответ здесь о семантике аппаратных уровней ограждений. Не упоминается, что они также предотвращают переупорядочение нагрузок, хранилищ или загрузок и хранилищ (в зависимости от забора) через ограждения как на уровне компилятора, так и на уровне оборудования.