Может кто-то давать легкое объяснение того, как 'Все Заборы' реализованы в Поточной обработке использования .NET. MemoryBarrier?

Я ясен на использовании MemoryBarrier, но не на том, что происходит негласно во времени выполнения. Кто-либо может дать хорошее объяснение того, что продолжается?

16
задан Andras Vass 22 March 2010 в 21:03
поделиться

2 ответа

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

Изгороди памяти необходимы, потому что текущие общие архитектуры не обеспечивают сильной модели памяти - x86 / x64 могут, например, переупорядочивать чтение относительно записи. (Более подробный источник - «Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32 , 8.2.2 Порядок памяти в процессорах P6 и более поздних семействах» ). Как пример из gazillions, алгоритм Деккера не сработает на x86 / x64 без ограждений.

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

Рискует чрезмерное упрощение: это может помочь визуализировать загрузки и сохранения, возникающие в результате потока инструкций, как грохочущее стадо диких животных. Когда они пересекают узкий мост (ваш процессор), вы никогда не можете быть уверены в этом порядок животных, так как некоторые из них будут медленнее, некоторые быстрее, некоторые догонят, некоторые отстанут. Если в начале - когда вы испускаете машинный код - вы разбиваете их на группы, помещая бесконечно длинные между ними, вы, по крайней мере, можете быть уверены, что группа A предшествует группе B.

Ограничения обеспечивают упорядочение операций чтения и записи.Формулировка неточная, но:

  • ограждение магазина "ожидает" завершения всех невыполненных операций сохранения (записи), но не влияет на нагрузки.
  • ограждение загрузки «ожидает» завершения всех невыполненных операций загрузки (чтения), но не влияет на хранилища.
  • полный забор «ждет» завершения всех операций сохранения и загрузки. Это имеет эффект, что чтение и запись до того, как ограждение будет выполнено, прежде чем записи и нагрузки, которые находятся на «другой стороне ограждения» (приходят позже, чем ограждение).

То, что JIT испускает для полного забора, зависит от архитектуры (ЦП) и того, какой порядок памяти он обеспечивает. Поскольку JIT точно знает, на какой архитектуре он работает, он может выдать правильную инструкцию ( с).

На моей машине x64 с .NET 4.0 RC это блокировка или .

            int a = 0;
00000000  sub         rsp,28h 
            Thread.MemoryBarrier();
00000004  lock or     dword ptr [rsp],0 
            Console.WriteLine(a);
00000009  mov         ecx,1 
0000000e  call        FFFFFFFFEFB45AB0 
00000013  nop 
00000014  add         rsp,28h 
00000018  ret 

Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32 Глава 8.1.2:

  • «... заблокированные операции сериализуют все невыполненные операции загрузки и сохранения (то есть дождаться их завершения)». ... "Заблокированные операции являются атомарными по отношению ко всем остальным операциям с памятью и всем внешне видимым событиям. {{1} } заблокированные инструкции. Заблокированные инструкции могут использоваться для синхронизации данных, записываемых одним процессором и считываемых другим процессором ".

  • Инструкции упорядочивания памяти удовлетворяют эту конкретную потребность. MFENCE можно было бы использовать в качестве полного барьера в приведенном выше случае (по крайней мере, теоретически - для одного, заблокированные операции могут быть быстрее , для двух он может привести к другому поведению ). MFENCE и его друзья могут быть найдены в главе 8.2.5 «Усиление или ослабление модели упорядочивания памяти» .

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

  • В главе 8.3 вы можете найти полные инструкции сериализации , такие как CPUID . Они также сериализуют последовательность инструкций: «Ничто не может передать инструкцию сериализации, и инструкция сериализации не может передавать никакую другую инструкцию (чтение, запись, инструкция выборка или ввод-вывод)» .

  • Если вы настроили память как сильную некэшированную (UC), , это даст вам сильную модель памяти : никакие спекулятивные или неупорядоченные обращения не будут разрешены, и все обращения будут отображаться на шине, поэтому нет необходимости выдавать инструкцию. :) Конечно, это будет чуть медленнее обычного.

...

Так что это зависит от. Если бы существовал компьютер с надежными гарантиями упорядочивания, JIT, вероятно, ничего не выдал бы.

IA64 и другие архитектуры имеют свои собственные модели памяти - и, следовательно, гарантии упорядочения памяти (или их отсутствия) - и свои собственные инструкции / способы работы с памятью хранения / упорядочением загрузки.

16
ответ дан 30 November 2019 в 22:17
поделиться

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

Переназначение инструкций программы может происходить на нескольких этапах:

  1. Оптимизация компилятора C#/VB.NET/F#
  2. JIT-оптимизация компилятора
  3. Оптимизация процессора.

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

  1. Ограждения загрузки - гарантируют, что никакие инструкции CPU загрузки не пересекаются с ограждениями
  2. Ограждения хранения - гарантируют, что никакие инструкции CPU хранения не пересекаются с ограждениями
  3. Полные ограждения - гарантируют, что никакие инструкции CPU загрузки или хранения не пересекаются с ограждениями

В .NET Framework существует множество способов создания ограждений: Interlock, Monitor, ReaderWriterLockSlim и т.д.

Thread.MemoryBarrier создает полное ограждение как на уровне JIT-компилятора, так и на уровне процессора.

4
ответ дан 30 November 2019 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: