Безопасно ли ссылочное назначение? - PullRequest
35 голосов
/ 06 марта 2011

Я создаю многопоточный кеш в C #, который будет содержать список объектов Car:

public static IList<Car> Cars {get; private set;}

Мне интересно, безопасно ли менять ссылку в потоке без блокировки?

, например

private static void Loop()
{
  while (true)
  {
    Cars = GetFreshListFromServer();
    Thread.Sleep(SomeInterval);
  }
}

По сути, все сводится к тому, является ли присвоение новой ссылки на автомобили атомарным или нет, я думаю.

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

Ответы [ 2 ]

59 голосов
/ 06 марта 2011

Да, эталонные обновления гарантированно являются атомарными в спецификации языка.

5.5 Атомность ссылок на переменные

Чтение и запись следующих типов данных являются атомарными: типы bool, char, byte, sbyte, short, ushort, uint, int, float и reference. Кроме того, чтение и запись перечислимых типов с базовым типом в предыдущем списке также являются атомарными. Чтение и запись других типов, включая long, ulong, double и decimal, а также определяемые пользователем типы, не гарантированно являются атомарными.

Однако внутри замкнутого цикла вы можете быть укушенным при кэшировании регистров. В этом случае маловероятно, если только вызов метода не встроен (что может произойти). Лично я бы добавил lock, чтобы сделать его простым и предсказуемым, но volatile может помочь и здесь. И обратите внимание, что полная безопасность потоков - это больше, чем просто атомарность.

В случае с кешем, я бы лично посмотрел на Interlocked.CompareExchange - то есть попытался обновить, но в случае неудачи повторить работу с нуля (запуск от нового значения) и попробуйте снова.

0 голосов
/ 24 апреля 2015

В ответе @Marc Gravell, как указано в C # Language Spec 5.5, важно знать, что подразумевается под термином «пользовательский тип».Я не нашел четкого определения этого использования в C # Language Spec.В UML и, на обычном языке, класс является экземпляром типа.Но в контексте спецификации языка C # это значение неясно.

Раздел справки по языку Visual Basic «Типы, определенные пользователем» (на https://msdn.microsoft.com/en-us/library/cec05s9z.aspx) написано

«Предыдущие версии Visual Basic поддерживают определяемый пользователем тип (UDT). Текущая версия расширяет UDT до структуры.»

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

Но ....

В соответствии с разделом «Типы» раздела «Руководство по программированию в C #» (по адресу https://msdn.microsoft.com/en-us/library/ms173104.aspx):

«Типичная программа на C # использует типы из библиотеки классов, а также определяемые пользователем типы»

, что подразумевает, что класс является определяемым пользователем типом. Позже он приводит пример «сложного пользовательского типа.определенные типы: "

MyClass myClass;

, что означает, что" MyClass "является определяемым пользователем типом. И позже он говорит:

"Каждый тип в CTS определяется как тип значения или ссылочный тип. Это включает все пользовательские типы в .NEБиблиотека классов T Framework и , а также ваши собственные определяемые пользователем типы

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

И, наконец, есть этот элемент Stackoverflow, в котором значениеэтого термина обсуждается безрезультатно: Как определить, является ли свойство пользовательским типом в C #?

Поэтому, чтобы быть в безопасности, я вынужден рассмотреть все классы, либоте, которые я создаю, или те, которые найдены в .Net Framework, все являются пользовательскими типами и, следовательно, не являются потокобезопасными для назначения, потому что в разделе 5.5 спецификации языка C # говорится:

Читаети записи ... а также пользовательских типов, как гарантируют, не будут атомарными.

К сожалению, разговорный термин используется в точной спецификации, такой как Спецификация языка C #.из этой двусмысленности, чтобы быть поточно-ориентированным, я могу писать менее оптимальный код, чем это было бы возможно, если бы выяснилось, что «определяемый пользователем тип» не включает классы CLR.

Поэтому я прошу дальнейшие разъяснения этого ответа на стек, поскольку его текущая основа для ответа оставляет эту существенную неоднозначность.В его нынешнем виде ответ на вопрос " Является ли справочное назначение безопасным для потоков? ", по-видимому, " NO ".

...