.NET изменчива.Чтение / запись и блокируемая область


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

Например, представьте, что у меня есть массив и счетчик.
long counter = 0;
var values = new double[1000000];

values[42] = 3.1415;
// Is this line needed instead of simple assignment above,
// or the implicit full-fence of Interlocked will guarantee that 
// all threads will see the values[42] after interlocked increment?
//Volatile.Write(ref values[42], 3.1415);
Interlocked.Increment(ref counter);

Делает блокированный инкремент гарантирует тот же результат, как если бы я использовал Volatile.Write(ref values[42], 3.1415); вместо values[42] = 3.1415;.

Что делать, если у меня есть массив ссылочные типы, например некоторые POCO, и устанавливают поля экземпляра перед блокируемым приращением. Применяется ли неявное полное ограждение ко всем операциям чтения / записи из этого потока до него или только к счетчику?

Я реализую масштабируемую схему чтения/записи и нашел следующее утверждение в посте Джо Даффи:

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

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

1 2

1 ответ:

Чего вам, вероятно, не хватает, так это понимания заборов. Это лучший ресурс, чтобы прочитать о них: http://www.albahari.com/threading/part4.aspx

Короткий ответ - Interlocked.Increment выдает полный забор, который не зависит от переменной, которую он обновляет. Я считаю, что Volatile.Write выдает половину забора. Половину забора можно построить из Thread.MemoryBarrier. Когда мы говорим, что Interlocked.Increment выдает полный забор, это означает, что Thread.MemoryBarrier вызывается до и после операции. Volatile.Write вызовы Thread.MemoryBarrier Перед записью и Volatile.Read после. Ограждения определяют, когда доступ к памяти может быть переупорядочен (и это не зависит от переменной, поскольку Thread.MemoryBarrier не имеет параметров).