Опорное назначение является атомным, так почему заблокирован. Exchange (Ref Object, объект) необходимо?

StackOverflow https://stackoverflow.com/questions/2192124

Вопрос

В моем многопоточном веб-сервисе ASMX у меня было классное поле _ALLDATA моего собственного типа SystemData, которая состоит из немногих List<T> а также Dictionary<T> отмечен как volatile. Отказ Системные данные (_allData) обновляется время от времени, и я делаю это, создавая другой объект под названием newData и заполните его структуры данных новыми данными. Когда это сделано, я просто назначаю

private static volatile SystemData _allData

public static bool LoadAllSystemData()
{
    SystemData newData = new SystemData();
    /* fill newData with up-to-date data*/
     ...
    _allData = newData.
} 

Это должно работать, поскольку назначение является атомным и потоком, которые имеют ссылку на старые данные, которые продолжают использовать его, а остальные имеют новые системные данные сразу после назначения. Однако моя коллега сказала, что вместо использования volatile Ключевое слово и простое ассигнование я должен использовать InterLocked.Exchange Потому что он сказал, что на некоторых платформах он не гарантируется, что ссылочное назначение атомное. Кроме того: когда я объявляю the _allData поле volatile то

Interlocked.Exchange<SystemData>(ref _allData, newData); 

ПРЕДУПРЕЖДЕНИЕ ПРЕДУПРЕЖДЕНИЯ "Ссылка на волатильное поле не будет рассматриваться как нестабильная" Что я должен думать об этом?

Это было полезно?

Решение

Здесь есть многочисленные вопросы. Учитывая их один за раз:

Опорное назначение является атомным, так почему заблокирован. Exchange (Ref Object, объект) необходимо?

Справочное назначение атомное. Interlocked.exchange не делает только ссылки. Он делает чтение текущего значения переменной, скрывает старое значение и назначает новое значение переменной, все как атомную операцию.

Мой коллега сказал, что на некоторых платформах он не гарантируется, что ссылочное назначение атомное. Был ли мой коллега правильно?

Нет. Осредоточенное задание гарантированно будет атомным на всех .NET платформ.

Мой коллега рассуждает от ложных помещений. Значит ли это, что их выводы неверны?

Не обязательно. Ваш коллега может дать вам хороший совет по плохую причину. Возможно, есть какая-то другая причина, по которой вы должны использовать Interlocked.exchange. Бесплатное программирование без блокировки безумно трудно и в тот момент, когда вы отправляетесь от хорошо обоснованных практик, поддерживаемых экспертами в области, вы находитесь в сорняках и рискуем к худшему родаму расы. Я не являюсь экспертом в этой области, ни эксперта по вашему коду, поэтому я не могу сделать суждение так или иначе.

ПРЕДУПРЕЖДЕНИЕ ПРЕДУПРЕЖДЕНИЯ "Ссылка на волатильное поле не будет рассматриваться как нестабильная" Что я должен думать об этом?

Вы должны понимать, почему это проблема в целом. Это приведет к пониманию того, почему предупреждение неважно в этом конкретном случае.

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

(Я предполагаю, что вы все это понимаете. Если у вас нет подробного понимания значения волатильного и того, как оно влияет на семантику Cache процессор, то вы не понимаете, как это работает и не должно использовать волатильные. Бесплатные программы очень трудно получить правильно; убедитесь, что ваша программа права, потому что вы понимаете, как это работает, а не в счет несчастных случаев.)

Теперь предположим, что вы делаете переменную, которая представляет собой псевдоним летучего поля, передавая ref в это поле. Внутри называемого метода компилятор не имеет никаких причин, что нужно знать, что ссылка должна иметь летучную семантику! Компилятор будет весело генерировать код для метода, который не выполняет правила для летучих полей, но переменной является волатильное поле. Которые могут полностью разрушить логику без блокировки; Предположение всегда в том, что летующее поле всегда Доступ к летучей семантике. Не имеет смысла лечить его как волатильным иногда, а не в других случаях; вы должны всегда быть последовательным, иначе вы не можете гарантировать согласованность в других доступах.

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

Конечно, заблокирован. Exchange является написано, чтобы ожидать летучего поля и делать правильные вещи. Поэтому предупреждение вводит в заблуждение. Я очень сожалею об этом; То, что мы должны были сделать, это реализовать какой-то механизм, посредством которого автор метода, такого как interlocked.exchange может поставить атрибут на метод, говорящий «Этот метод, который принимает REF, обеспечивающую волатильную семантику на переменной, поэтому подавляет предупреждение». Возможно, в будущей версии компилятора мы сделаем это.

Другие советы

Либо ваша коллега ошибается, или он знает что-то, что спецификация языка C # не так.

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

«Читает и пишеты из следующих типов данных являются атомными: Bool, Char, Byte, Sbyte, Short, Ushort, Uint, int, float и ссылочные типы".

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

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

Interlocked.exchange <T>

Устанавливает переменную указанного типа t до указанного значения и возвращает исходное значение, как атомная операция.

Он меняется и возвращает первоначальное значение, это бесполезно, потому что вы только хотите изменить его, и, как сказал Гуффа, он уже атомной.

Если Profiler не доказал его, чтобы быть узким местом в вашем приложении, вы должны рассмотреть неразреженные замки, легче понимать и доказать, что ваш код прав.

Iterlocked.Exchange() Не просто атомный, это также заботится о видимости памяти:

Следующие функции синхронизации используют соответствующие барьеры для обеспечения порядка памяти:

Функции, которые входят или оставляют критические разделы

Функции, которые сигнализируют объекты синхронизации

Ожидание функций

Заблокированные функции

Синхронизация и многопроцессорные проблемы

Это означает, что в дополнение к атомности он гарантирует, что:

  • Для потока, вызывающего это:
    • Нет переупорядочения инструкций (компилятором, время выполнения или оборудованием).
  • Для всех потоков:
    • Нет читается к памяти, который произойдет до того, как эта инструкция увидит, что изменение этой инструкции сделано.
    • Все чтения после этой инструкции увидят изменения, сделанные этой инструкцией.
    • Все пишет в память после того, как эта инструкция произойдет после того, как это изменение инструкции достигло основной памяти (путем промывки этой инструкции изменение в основную память, когда она выполнена, и не позволяйте аппаратному обеспечению вспомогательно его на синхронизации).
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top