Вопрос по multithreading, concurrency, c# – Свойства имеют изменчивый эффект?

12

В коде ниже будет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, Будет ли онalways быть так? Не превратит свойство в энергонезависимое поле, которое вызоветread1 быть равнымread2 несмотря на этоFlag был изменен между чтениями?

Я не вижу причин, чтобы это былоguaranteed, Конечно,volatile также, как правило, не совсем то, о чем думают люди. Лично я бы посмотрел наlock или жеInterlocked если это имеет значение. Marc Gravell♦

Ваш Ответ

6   ответов
3

Да, это можно изменить естественно.

Даже в предоставленном коде не гарантируется, чтоread1 будет равноread2.

Учитывая, что между тем/* some more code */ выполняется,Flag могут быть затронуты другими потоками.

EDIT

Равенствоread1 а такжеread2 не имеет никакого отношения к встраиванию или нет,Flag этоboolтак что это тип значения. Так

  • var read1 = Flag; //let's say read1 TRUE
  • Flag = False
  • var read2 = Flag; //read2 is FALSE, but read1 remains TRUE

Это действительно вnon Многопоточная среда тоже, потому что вы работаете с типом значения.

Если это не то, о чем вы просите, уточните.

Я думаю, что, учитывая изменение OP, он спрашивает, что предполагается изменение потокаFlag в то время как/* some more code */ выполняется, этоguaranteed тотread2 подхватит это изменение.
@shtriha: я отредактировал свой ответ, пожалуйста, посмотрите
1

Отсутствие энергозависимости для автопортретов разочаровывает. Я обнаружил, что при использовании структуры с [StructLayout (LayoutKind.Sequential, Pack = 4)] и Marshal.PtrToStructure байтовый макет не сохраняется должным образом, если используется автоматическое свойство. Что я сделал, так это использовал частные поля поддержки и поместил свойства в конец.

15

Нет, собственности нет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();
    }
}

Сборка в режиме Release приведет к тупику программы, что доказывает, чтоFlag не имеет изменчивого поведения (то есть он оптимизируется между чтениями).

Заменаpublic bool Flag { get; set; } сpublic volatile bool Flag; заставит программу завершиться правильно.

Как насчет инкапсулированного летучего поля? частный волатильный флаг bool; и флаг свойства {get {return flag; }, установите {флаг = значение; }}?
@ILIA BROUDNO: Этот пример зависит от среды, хотя он должен быть достаточно согласованным для всех версий .Net, если у вас многоядерный компьютер. Я только что проверил это в VS 2013, .Net 4.5 на четырехъядерном Xeon, и я все еще могу воспроизвести его. Убедитесь, что & quot; оптимизируйте код & quot; включен в свойствах проекта при его создании.
@ Pedro77: Это будет работать.
Другая возможность состоит в том, чтобы сделать фоновое поле изменчивым. Таким образом, вы все еще можете использовать тот же модификатор набора, что и внутренний.
Очень интересный момент, но в моем тесте Release версия вашего точного кода не заблокировалась. Запуск в Visual Studio 2013 в новом консольном проекте, поэтому параметры оптимизации соответствуют настройкам по умолчанию. Я понимаю, что это зависит от реализации, независимо от того, оптимизируется она или нет, но мне трудно поверить, что фактическое значение переменной не будет проверено в то время как (! Flag), и вместо этого будет использоваться ее начальное значение. Особенно, когда компилятор может определить, что значение действительно меняется.
1

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

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

1

Если флаг может быть изменен из других потоков, нет гарантии, что read1 и read2 будут одинаковыми. Вы должны будете использовать монитор / мьютекс, окружающий ваш код, а также убедиться, что установщик флага также учитывает этот мьютекс.

гарантия, что они будут разными? Конечно, нет. Они могут отличаться в зависимости от выполняемого кода вместе с вашим кодом в MultithreadedMethod. Если есть другой поток, манипулирующий флагом, они могут отличаться.
Да, но есть ли гарантия, что read1 и read2 будут разными. shtriha
-1

Согласнодокументация

The volatile keyword indicates that a field can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread. ... Using the volatile modifier ensures that one thread retrieves the most up-to-date value written by another thread.

Авто-свойства объявляют закрытое поле того же типа, что и свойство, и получают к нему доступ через геттер и сеттер. Закрытые свойства не имеют каких-либо специальных модификаторов, поэтому они не будут вести себя как изменчивое поле.
А как насчет авто-собственности? Это не может быть изменчивым. Но будет ли он вести себя как изменчивый? shtriha
Жаль, что вы не можете использоватьvolatile на autoproperty, чтобы заставить основное поле бытьvolatile, Извините, ваш ответ не отвечает на вопрос, только ваши комментарии ;-).

Похожие вопросы