Подтвердить что ты не робот

У свойств есть летучий эффект?

В приведенном ниже коде 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 был изменен между чтением?

4b9b3361

Ответ 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 указывает, что поле может быть изменено в программы, например, операционной системой, оборудованием или одновременно выполняющий поток.... Использование изменчивого модификатора гарантирует, что один поток обновленное значение, написанное другим потоком.