Чтение и запись свойств атома в С#?
Чтение и запись некоторых примитивных типов в С#, таких как bool
и int
, являются атомарными.
(См. раздел 5.5, "5.5 Атомарность ссылок на переменные" в Спецификации языка С#.)
Но как насчет доступа к таким переменным через свойства? Можно ли предположить, что они также будут атомарными и потокобезопасными? Например. Является ли чтение MyProperty
ниже атомарным и потокобезопасным?:
public bool MyProperty { get { return _foo; } }
А как насчет автоматически реализованных свойств?
public bool MyProperty { get; }
Ответы
Ответ 1
Вам нужно провести более четкое различие между "атомарным" и "потокобезопасным". Как вы говорите, записи являются атомарными для большинства встроенных типов значений и ссылок.
Однако это не значит, что они потокобезопасны. Это просто означает, что если значения "A" и "B" написаны, поток никогда не увидит что-то промежуточное. (например, изменение от 1 до 4 никогда не отображает 5 или 2 или любое значение, отличное от 1 или 4.) Это не означает, что один поток будет видеть значение "B", как только он будет записан в переменную. Для этого вам нужно взглянуть на модель памяти с точки зрения волатильности. Без барьеров памяти, обычно получаемых с помощью блокирующих и/или изменчивых переменных, запись в основную память может задерживаться, и считывания могут быть расширены, эффективно предполагая, что значение не изменилось с момента последнего чтения.
Если у вас есть счетчик, и вы попросили его получить его последнее значение, но никогда не получили последнее значение из-за нехватки барьеров в памяти, я не думаю, что вы могли бы разумно назвать это потокобезопасным, хотя каждая операция может быть атомарный.
Это не имеет ничего общего с свойствами, но свойства - это просто методы с синтаксическим сахаром вокруг них. Они не дают никаких дополнительных гарантий вокруг резьбы. Модель памяти .NET 2.0 имеет больше гарантий, чем модель ECMA, и возможно, что она обеспечивает гарантии при входе и выходе метода. Эти гарантии должны также относиться и к свойствам, хотя я бы нервничал по поводу интерпретации таких правил: иногда бывает трудно рассуждать о моделях памяти.
Ответ 2
Я немного не понимаю, что вы здесь задаете. Кажется, вы могли задавать 1 из 2 вопросов.
- Является ли чтение
_foo
при вызове атома MyProperty?
- Является ли возвращаемое значение MyProperty атомарным?
Для # 1 ответ да. Поскольку спецификация языка С# (и CLI) указывает, что чтение и запись переменных определенных определенных типов гарантированно будет атомарным. Тип "bool" является одним из этих типов.
Что касается №2, лучшим местом для просмотра является раздел 12.6.6 спецификации CLI. В нем указано, что
Соответствующий CLI должен гарантировать, что доступ для чтения и записи к правильно выровненным ячейкам памяти не превышает размер собственного слова (размер типа native int) - атомный
Учитывая использование возвращаемого значения MyProperty, вы должны либо читать, либо записывать значение, поэтому можно предположить, что оно задано атомарно.
Ответ 3
Если вы изучите автоматически сгенерированный код, вы увидите, что автоматически сгенерированные свойства НЕ являются потокобезопасными - они просто get/set для сгенерированного поля. На самом деле, это было бы слишком большим успехом, чтобы сделать это (особенно когда это не нужно).
Кроме того, если вы планируете получать значения int/bool из нескольких потоков, тогда вы должны пометить его (поле) как volatile, Это в основном предотвращает проблемы многопоточности, связанные с регистрами CPU. (Это помимо блокировки, а не альтернативы)
Ответ 4
Атоматичность просто означает, что если более чем один поток записывает в переменную, его значение не будет искажено (например, если оно занимает два байта, вы никогда не получите нить один старший байт и нить два младшего байта). Он не означает, что переменная является потокобезопасной. Вы все равно можете получить обычные проблемы с потоками одного потока, не видя чужих изменений и т.д.
Для обеспечения безопасности потоков вам необходимо использовать блокировку (или неустойчивую, но это сложнее рассуждать). Нет ничего особенного в свойствах - они также должны быть явно потокобезопасными.
Ответ 5
Я бы не подумал. Свойства - это, по сути, просто методы с немного синтаксического сахара на них, чтобы сделать их немного легче работать. Таким образом, по умолчанию они не более потокобезопасны, чем обычный вызов метода (то есть вообще не потокобезопасный).
Ответ 6
Вы можете поместить что-либо в свойство, например
Public Property foo() As Boolean
Get
goToLunch()
barbecueRibs()
return m_foo
End Get
Set(ByVal value As Boolean)
takeANap()
accessDatabase()
messUpOtherVariables()
m_foo = value
End Set
End Property