С ++ Память Барьеры для Атомики - PullRequest
27 голосов
/ 13 января 2012

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

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

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

Ответы [ 2 ]

29 голосов
/ 13 января 2012

И 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-receive и store-release.

3 голосов
/ 13 января 2012

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

...