Генераторы барьера памяти

Читая учебник Джозефа Албахари о потоках, в качестве генераторов барьеров памяти упоминаются следующие:

  • C# 's lock заявление (Monitor.Enter/Monitor.Exit)
  • Все методы на Interlocked учебный класс
  • Асинхронные обратные вызовы, которые используют пул потоков - к ним относятся асинхронные делегаты, обратные вызовы APM и продолжения задач
  • Установка и ожидание на сигнальной конструкции
  • Все, что зависит от сигнализации, например, запуск или ожидание задачи

Кроме того, Ханс Пассант и Брайан Гидеон добавили следующее (предполагая, что ни одна из них не вписывается ни в одну из предыдущих категорий):

  • Запуск или пробуждение потока
  • Переключение контекста
  • Thread.Sleep()

Мне было интересно, если этот список был завершен (если полный список можно было бы даже практически сделать)

РЕДАКТИРОВАТЬ дополнения предложил:

  • Изменчивый (чтение подразумевает забор приобретения, написание подразумевает забор выпуска)

3 ответа

Решение

Вот мой взгляд на эту тему и попытка представить квази-полный список в одном ответе. Если я сталкиваюсь с другими, я буду время от времени редактировать свой ответ.

Механизмы, которые в целом согласованы для создания неявных барьеров:

  • Все Monitor методы класса, включая ключевое слово C# lock
  • Все Interlocked методы класса.
  • Все Volatile методы класса (.NET 4.5+).
  • Наиболее SpinLock методы в том числе Enter а также Exit,
  • Thread.Join
  • Thread.VolatileRead а также Thread.VolatileWrite
  • Thread.MemoryBarrier
  • volatile ключевое слово.
  • Все, что запускает поток или вызывает выполнение делегата в другом потоке, включая QueueUserWorkItem, Task.Factory.StartNew, Thread.Start, компилятор поставляется BeginInvoke методы и т. д.
  • Использование механизма сигнализации, такого как ManualResetEvent, AutoResetEvent, CountdownEvent, Semaphore, Barrier, так далее.
  • Использование операций маршалинга, таких как Control.Invoke, Dispatcher.Invoke, SynchronizationContext.Post, так далее.

Механизмы, которые предполагаются (но не известны наверняка), чтобы вызвать неявные барьеры:

  • Thread.Sleep (предложено мной и, возможно, другими в связи с тем, что код, который имеет проблему с барьером памяти, может быть исправлен с помощью этого метода)
  • Thread.Yield
  • Thread.SpinWait
  • Lazy<T> в зависимости от того LazyThreadSafetyMode указан

Другие заметные упоминания:

  • Обработчики добавления и удаления по умолчанию для событий в C#, так как они используют lock или же Interlocked.CompareExchange,
  • x86 магазины имеют семантику релизов
  • Реализация CLI в Microsoft имеет семантику ограничения выпуска при записи, несмотря на то, что спецификация ECMA не предписывает это.
  • MarshalByRefObject кажется, подавляет определенные оптимизации в подклассах, которые могут заставить его выглядеть так, как будто присутствует неявный барьер памяти. Спасибо Гансу Пассанту за то, что он открыл это и обратил мое внимание. 1

1 Это объясняет почему BackgroundWorker работает правильно, не имея volatile на базовое поле для CancellationPending имущество.

Кажется, я вспоминаю, что реализации методов Thread.VolatileRead и Thread.VolatileWrite фактически вызывают полные заборы, а не половину заборов.

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

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

volatile Ключевое слово действует как барьер памяти тоже. См. http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx

Другие вопросы по тегам