У свойств есть летучий эффект?
В приведенном ниже коде read1
всегда будет read2
, если свойство Flag
может быть изменено из других потоков? Озабоченность здесь заключается в том, что Flag
может быть вложен.
private bool Flag {get; set;}
public void MultithreadedMethod()
{
var read1 = Flag;
/* some more code */
var read2 = Flag;
}
UPD. Некоторые другие потоки могут изменять значение Flag
во время выполнения /* some more code */
. В этом случае read1
должен отличаться от read2
. Всегда ли так будет? Не приведет к включению свойства в энергонезависимое поле, которое приведет к тому, что read1
будет равно read2
, несмотря на то, что факт Flag
был изменен между чтением?
Ответы
Ответ 1
Нет, свойство не volatile
.
Пока я не смог получить удовлетворительную демонстрацию для вашего первоначального сценария, этот альтернативный метод должен хорошо показать выражение:
class Program
{
public bool Flag { get; set; }
public void VolatilityTest()
{
bool work = false;
while (!Flag)
{
work = !work; // fake work simulation
}
}
static void Main(string[] args)
{
Program p = new Program();
var t = new Thread(p.VolatilityTest);
t.Start();
Thread.Sleep(1000);
p.Flag = true;
t.Join();
}
}
Построение этого в режиме деблокирования сделает тупик программы, следовательно, доказательство того, что Flag
не имеет изменчивого поведения (т.е. получает "оптимизировано" между чтением).
Замена public bool Flag { get; set; }
на public volatile bool Flag;
приведет к правильной работе программы.
Ответ 2
Да, это можно изменить естественным образом.
Даже в коде, если он не гарантирует, что read1
будет равно read2
.
Учитывая, что при выполнении /* some more code */
Flag
могут влиять другие потоки.
EDIT
Равенство read1
и read2
не имеет ничего общего с вложением или нет, Flag
является bool
, поэтому это тип значения. Итак,
-
var read1 = Flag;
//let say read1 TRUE
-
Flag = False
-
var read2 = Flag;
//read2 является FALSE, но read1 остается TRUE
Это допустимо в многопоточной среде не, поэтому вы работаете с типом значения.
Если это не то, о чем вы просите, пожалуйста, уточните.
Ответ 3
если флажок можно изменить из других потоков, нет гарантии, что read1 и read2 будут одинаковыми. Вам нужно будет использовать монитор/мьютекс, окружающий ваш код, а также убедитесь, что установщик флагов также уважает этот мьютекс.
Ответ 4
Подводя итог другим ответам, в этой ситуации то, что происходит со значениями двух переменных после выполнения кода, не может быть предсказано. И то, и другое, потому что CLR и компилятор в основном являются черными ящиками для нас, и потому, что любое предсказание относительно результата состояния гонки - это действительно игра, которая в какой-то момент неизбежно ошибается.
Независимо от того, вы не можете писать такой код в многопоточной среде.
Ответ 5
Отсутствие волатильности для автопроизводства вызывает разочарование. Я обнаружил, что при использовании структуры с [StructLayout (LayoutKind.Sequential, Pack = 4)] и Marshal.PtrToStructure макет байта не сохраняется, как ожидалось, если используется автопроцессор. То, что я сделал, это использовать частные поля поддержки и поместить свойства в конец.
Ответ 6
В соответствии с документацией
Ключевое слово volatile указывает, что поле может быть изменено в программы, например, операционной системой, оборудованием или одновременно выполняющий поток.... Использование изменчивого модификатора гарантирует, что один поток обновленное значение, написанное другим потоком.