Когда использовать блокировку против MemoryBarrier в .NET - PullRequest
12 голосов
/ 05 января 2010

В .NET ключевое слово lock является синтаксическим сахаром около Monitor.Enter и Monitor.Exit, так что вы можете сказать, что этот код

lock(locker)
{
  // Do something
}

совпадает с

Monitor.Enter(locker);
try
{
  // Do Something
}
finally
{
  Monitor.Exit(locker);
}

Однако .NET Framework также включает класс MemoryBarrier, который работает аналогичным образом

Thread.MemoryBarrier();
//Do something
Thread.MemoryBarrier();

Я не совсем понимаю, когда мне захочется использовать Thread.MemoryBarrier вместо lock / Monitor версии? Меня еще больше смущает Учебное пособие по потокам , в котором говорится, что они функционируют одинаково.

Насколько я вижу, видимая разница не нуждается в блокирующем объекте, что, как я предполагаю, используя Monitor, вы могли бы сделать что-то между потоками, где MemoryBarrier находится в одном потоке.

Моя интуиция говорит мне, что другое ключевое отличие - MemoryBarrier только для переменных, а не для методов.

Наконец, это не связано с существующим вопросом Когда использовать «volatile» или «Thread.MemoryBarrier ()» в коде блокировки потока? (C #) , так как это фокусируется на ключевом слове volatile, которое, как я понимаю, используется.

1 Ответ

22 голосов
/ 05 января 2010

На мой взгляд, вы должны почти никогда использовать Thread.MemoryBarrier. Это используется для кода без блокировки - чтобы убедиться, что изменения, сделанные в одном потоке, видны другому без ущерба для стоимости блокировки. Он не управляет синхронизацией потоков, в отличие от lock. Я не понимаю, где в уроке Джо он говорит, что MemoryBarrier "функционирует так же", как и lock. Не могли бы вы объяснить, откуда именно у вас это впечатление?

На мой взгляд, низкоуровневый код без блокировок слишком сложен практически для всех, кроме разработчиков, основным навыком которых является параллелизм. Если я захочу написать некоторый код без блокировки, я буду использовать строительные блоки более высокого уровня , встроенные этими разработчиками (например, Parallel Extensions в .NET 4.0), вместо того, чтобы пытаться свернуть свой собственный.

Как пример, я недавно открыл глаза на точное значение volatile, которое не «всегда читать из основной памяти, всегда записывать напрямую в основную память». (В моем собственном учебнике по потокам до сих пор есть такое объяснение - что-то, что мне нужно исправить в какой-то момент.) Это гораздо более тонко, чем . Это означает, что некоторые моих предыдущих использований volatile вполне могут быть неправильными.

...