Является ли ссылочное назначение потоковым?

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

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

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

например.

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

В основном это сводится к тому, что присвоение новой ссылки на "Автомобили" является атомной или нет, я бы предположил.

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

Ответ 1

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

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

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

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

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

Ответ 2

В ответе @Marc Gravell, как указано в С# Language Spec 5.5, важно знать, что подразумевается под термином "определяемый пользователем тип". Я не нашел четкого определения w.r.t. это использование в языке С# Spec. В UML и в общем выражении класс является экземпляром типа. Но в контексте С# Language Spec это значение неясно.

Раздел ссылок на Visual Basic "Определенные пользователем типы" (в https://msdn.microsoft.com/en-us/library/cec05s9z.aspx) говорит

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

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

Но....

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

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

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

MyClass myClass;

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

"Каждый тип в CTS определяется как тип значения или ссылка тип. Сюда входят все пользовательские типы в классе .NET Framework библиотеки, а также ваши собственные пользовательские типы."

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

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

Поэтому, чтобы быть в безопасности, я вынужден рассматривать все Классы, созданные мной или те, которые содержатся в .Net Framework, все должны быть определенными пользователем типами, и поэтому Not Thread Safe для назначения, потому что он говорит в разделе 5.5 языка С#:

Считывание и запись... а также пользовательских типов не гарантируется атомарным.

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

Поэтому я прошу дать дополнительное разъяснение этому ответу stackoverflow, поскольку его текущая основа для ответа оставляет эту значительную двусмысленность. Как бы то ни было, ответ на вопрос " Является ли ссылочным назначением потокобезопасным?" кажется " НЕТ".