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

Погрешность памяти vs Блокированное влияние на тайники синхронизации кэшей памяти

Упрощенный вопрос:

Есть ли разница в синхронизации когерентности кэширования памяти (или "промывки" ), вызванной блокировкой операций по сравнению с барьерами памяти? Рассмотрим в С# - любые операции с блокировкой vs Thread.MemoryBarrier(). Я считаю, что есть разница.

Фон:

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

На самом деле я нашел несколько источников, в которых упоминается, что нет гарантии на непосредственность операции (гарантируется только предотвращение специфического переупорядочения). Например.

Wikipedia: "Однако, чтобы быть ясным, это не означает, что какие-либо операции будут завершены к моменту завершения барьера, гарантируется только ЗАВЕРШЕНИЕ завершения операций (когда они завершатся)"

Freebsd.org (барьеры специфичны для HW, поэтому я думаю, что конкретная ОС не имеет значения): "Балансы памяти просто определяют относительные порядок операций с памятью, они не гарантируют синхронизацию операций с памятью"

С другой стороны, блокированные операции - из их определения - приводят к немедленной очистке всех буферов памяти, чтобы гарантировать обновление последнего значения переменной. заставляет подсистему памяти блокировать всю строку кэша со значением, чтобы предотвратить доступ (включая чтение) из любого другого ЦП/ядра, пока операция не будет выполнена.

Правильно ли я ошибаюсь?

Отказ от ответственности:

Это эволюция моего первоначального вопроса здесь Возможность переменной свежести в .NET(volatile vs. volatile read)

EDIT1: Исправлено мое утверждение о блокированных операциях - встраивание текста.

EDIT2: Полностью удалить демонстрационный код + это обсуждение (поскольку некоторые жаловались на слишком много информации)

4b9b3361

Ответ 1

Чтобы понять операции с блокировкой С#, вам нужно понимать операции блокировки Win32.

"Чистые" операции блокировки влияют только на свежесть данных, непосредственно связанных с операцией.

Но в Win32 блокированные операции используются для обеспечения полного барьера памяти. Я считаю, что это в основном, чтобы не ломать старые программы на более новом оборудовании. Таким образом, InterlockedAdd выполняет две функции: блокировку add (очень дешево, не влияет на кеши) и полный барьер памяти (довольно тяжелый op).

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

Итак, теперь (в мире Win32) четыре версии почти всех: например. InterlockedAdd (полный забор), InterlockedAddAcquire (чтение забора), InterlockedAddRelease (запись забора), чистый InterlockedAddNoFence (без забора).

В мире С# существует только одна версия, и она соответствует "классическому" InterlockedAdd, что также делает полный забор памяти.

Ответ 2

Короткий ответ: операции CAS (с блокировкой) были (и, скорее всего, будут) самыми быстрыми флешерами кэшей.

Фон:  - Операции CAS поддерживаются в HW единой инструкцией без вмешательства. По сравнению с барьером памяти вызовов вызовов, который можно поменять местами сразу после размещения барьера, но перед выполнением каких-либо чтений/записей (так что согласованность, обеспечиваемая для барьера, по-прежнему выполняется).  - Операции CAS основаны на большинстве (если не на всех) строках синхронизации высокого уровня (мьютексы, sempahores, locks - посмотрите на их реализацию, и вы найдете операции CAS). Они вряд ли будут использоваться, если они не гарантируют немедленную согласованность состояния поперечного потока или если будет другой, более быстрый механизм (ы)

Ответ 3

По крайней мере, на устройствах Intel последовательность операций машинного кода может быть префикс префикса LOCK, который гарантирует, что следующая операция рассматривается как атомарная, даже если базовый тип данных не будет помещаться на шину данных за один раз, для Например, LOCK REPNE SCASB сканирует строку байтов для нулевого нуля и не будет прервана другими потоками. Насколько мне известно, конструкция "Барьер памяти" - это, в основном, спин-блокировка на основе CAS, которая заставляет поток ждать некоторого состояния, которое необходимо выполнить, например, ни один другой поток не должен выполнять какую-либо работу. Это явно конструкция более высокого уровня, но не заблуждайтесь там, там проверка состояния и, вероятно, будет атомарной, а также, вероятно, будет защищена CAS, вы все равно будете платить цену на кеш-карту, когда вы достигнете барьер памяти.