.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 ответ:
Чего вам, вероятно, не хватает, так это понимания заборов. Это лучший ресурс, чтобы прочитать о них: 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
не имеет параметров).