Атомарность ссылок на объекты - PullRequest
0 голосов
/ 25 января 2009

Я только что натолкнулся на вопрос - возможен ли безопасный доступ к объекту через потоки в C #.

например. с кодом

//Somewhere long ago
MyClass myVar = new MyClass("First Instance");

//Then later, happening at the same time
//In thread one
myVar = new MyClass("Second Instance");

//In thread two
myVar.PrintName();

Меня не волнует, используется ли первый или второй экземпляр, но возможно ли, что myVar в какой-то момент вообще недопустим (например, указывает на несуществующее местоположение, потому что, возможно, ссылка на объект обновляется только частично раньше использовался в другой теме)


Дополнительный вопрос о замках:

Если я оставляю блокировку - тогда все незавершенные записи записываются в память?

Мой вопрос здесь: если я ссылаюсь на переменную в блокировке, я знаю, что только один поток может получить доступ к блокировке одновременно - но может ли случиться так, что я записываю переменную в одном потоке (а запись выполняется только в кеш), а после этого в другом потоке даже внутри блокировки получаю старое значение переменной (потому что кеш не зафиксирован или у меня еще есть старое значение в кеше этого потока)?

Ответы [ 4 ]

1 голос
/ 27 января 2009

Я знаю, что ваш вопрос касается .NET, и я не могу сказать вам ответ там. Однако в Java этот код определенно НЕ будет безопасным.

Риск состоит в том, что переупорядочение кода (шаг оптимизации) приведет к обновлению ссылки на объект ДО того, как конструктор завершит работу - следовательно, второй поток может увидеть частично созданную версию второго объекта.

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

Как я уже сказал, я недостаточно знаю модель памяти .NET, чтобы понять, будет ли в .NET такая же проблема.

1 голос
/ 26 января 2009

к вашему первому. Это почти наверняка безопасно, но я бы запер его, тем не менее.

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

Edit: Из вашего комментария я вижу, что кэш процессора - это то, к чему вы обращаетесь.

Многоядерное и многопроцессорное оборудование гарантирует, что любые устаревшие данные в кеше не будут использоваться.

0 голосов
/ 26 января 2009

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

0 голосов
/ 26 января 2009

Пример кода в вашем вопросе является потокобезопасным. Очевидно, в зависимости от того, что вы делаете внутри этого конструктора, но «в целом» ссылка myVar будет действительна (в общем случае есть некоторые вещи низкого уровня, которые вы могли бы сделать, например FormatterServices и т. Д.). Новый объект будет создан с помощью конструктора и будет автоматически возвращен в нужный поток. Для меня это один из лучших способов убедиться, что код является поточно-ориентированным, путем создания новых объектов в каждом потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...