2012-01-12 6 views
27

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

  • Окно MemoryBarrier();
  • Забор _mm_mfence();
  • Рядных сборки asm volatile ("" : : : "memory");
  • Характеристической _ReadWriteBarrier();

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

+4

Вы забыли про C++ 11s 'atomic_thread_fence' – Grizzly

+0

Ну, вот что это заставляет ... у нас есть свой собственный шаблонный шаблонный объект для интегральных типов, и я хочу переключиться на стандартную атомику C++ 11. Прежде чем это сделать, я хочу понять основную реализацию того, как они работают на самом деле. – AJG85

ответ

28

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

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

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

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

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

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

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

+0

безупречный! спасибо, это очень помогло. – AJG85

3

См. Мой ответ here на уровне аппаратного уровня ограждений. Что не упомянуто, что они также препятствуют переупорядочению нагрузок, складов или грузов. & магазины (в зависимости от забора) через заборы, как на уровне компилятора, так и на уровне оборудования.