Здравствуйте, kkav, Вы писали:
K>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, mihailik, Вы писали:
M>>>Ещё немного из свежего блога:
M>>>volatile and MemoryBarrier() Brad Adams Blog
S>> Спасибо. Нужно будет попобовать.
K>По указанной ссылке написано:
K>K> public static Singleton Value {
K> get {
K> if (Singleton.value == null) {
K> lock (syncRoot) {
K> if (Singleton.value == null) {
K> Singleton newVal = new Singleton();
K> // Insure all writes used to construct new value have been flushed.
K> System.Threading.Thread.MemoryBarrier();
K> Singleton.value = newVal; // publish the new value
K> }
K> }
K> }
K> return Singleton.value;
K> }
K>}
K>
Там в одном из комментариев более правильная версия есть с двумя memory barriers.
K>Почему System.Threading.Thread.MemoryBarrier();
K>Выполняется до Singleton.value = newVal;
K>а не после него, если мы боимся, что к моменту выполнения
K>другим потоком (lock (syncRoot) { if (Singleton.value == null) ...)
K>Singleton.value еще не будет еще присвоено?
K>Не логичнее ли высвободить кэш после присвоения?
Допустим, делается так как ты предлагаешь. Тогда есть следующий вариант развития событий: первый поток входит в lock выделяет Singleton и инициализирует Singleton.value, но замещается вторым потоком прям перед вызовом MemoryBarrier(). Второй поток проверяет Singleton.value, его значение уже не null, и оно тут-же возвращается из функции. Далее второй поток пытается использовать тот объект Singleton, который он получил, но так как сконструированный объект Singleton еще находится в кэше первого потока (пусть эти потоки выполняются на разных процессорах), то второй поток, думая, что он обращается к памяти Singleton'а, на самом деле читает память, в которой еще мусор. Вот так.
Вопрос этот вообщем очень интересный. Почитай пост Vance Morrison'а (ссылка в блоге Брада) про моделирование поведения памяти с помощью перестановок чтения/записи. А так же про модель памяти CLR в блоге Chris Brumme'а.