C# 属性是否具有挥发性影响?

C# 属性是否具有挥发性影响?,c#,multithreading,concurrency,C#,Multithreading,Concurrency,在下面的代码中,read1是否始终等于read2,前提是可以从其他线程更改属性标志?这里关注的是标志可能会内联 private bool Flag {get; set;} public void MultithreadedMethod() { var read1 = Flag; /* some more code */ var read2 = Flag; } UPD:在执行/*更多代码*/期间,其他一些线程可能会更改标志的值。在这种情况下,read1应该与

在下面的代码中,
read1
是否始终等于
read2
,前提是可以从其他线程更改属性
标志
?这里关注的是
标志
可能会内联

private bool Flag {get; set;}

public void MultithreadedMethod()
{
    var read1 = Flag;

    /* some more code */

    var read2 = Flag;    
}

UPD:在执行
/*更多代码*/
期间,其他一些线程可能会更改
标志的值。在这种情况下,
read1
应该与
read2
不同。会一直如此吗?内联不会将属性转换为非易失性字段,从而导致
read1
等于
read2
,尽管在读取之间更改了
标志

是,它可以自然更改

即使在提供的代码中,
read1
也不能保证等于
read2

考虑到同时执行的
/*更多的代码*/
标志
可能会受到其他线程的影响

编辑

read1
read2
的相等性与内联与否无关,
Flag
是一个
bool
,因此它是一个值类型。所以

  • var read1=Flag//假设read1为TRUE
  • Flag=False
  • var read2=Flag//read2为FALSE,但read1仍为TRUE
这在多线程环境中也有效,因为您操作的是值类型


如果这不是您想要的,请澄清。

如果可以从其他线程更改标志,则不能保证read1和read2是相同的。您必须在代码周围使用监视器/互斥体,并确保标志设置器也尊重该互斥体。

根据

volatile关键字表示可以在中修改字段 通过诸如操作系统、硬件或 并发执行线程。 ... 使用volatile修饰符可确保一个线程检索最多的 由另一个线程写入的最新值。


综上所述,在这种情况下,无法预测代码执行后两个变量的值会发生什么变化。因为CLR和编译器对我们来说基本上都是黑匣子,而且因为任何关于竞争条件结果的预测都是一场赌博,在某一点上肯定是错误的


无论如何,您不能在多线程环境中编写此类代码。

否,该属性不是易变的

虽然我未能为您的初始场景获得令人满意的演示,但此替代方法应能很好地证明该陈述:

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模式下构建该函数将使程序死锁,从而证明
标志
不具有易失性行为(即,它在读取之间得到“优化”)


public bool标志{get;set;}
替换为
public volatile bool标志将使程序正确终止。

自动属性缺少volatile令人失望。我发现当使用带有[StructLayout(LayoutKind.Sequential,Pack=4)]和Marshal.PtrToStructure的结构时,如果使用autoproperty,字节布局不会像预期的那样保留。我所做的是使用私有支持字段,并将属性放在末尾。

是的,但有没有保证read1和read2会不同。有没有保证它们会不同?当然不是。它们可能会有所不同,这取决于在多线程方法中与代码一起运行的代码。如果有另一个线程操作标志,它们可能会不同。那么auto属性呢?。这是不可能做到的。但是它会表现为易失性吗?自动属性声明一个与属性类型相同的私有字段,并通过getter和setter访问它。私有属性没有任何特殊的修饰符,因此它的行为不会像易失性字段。太糟糕了,您不能在自动属性上使用
易失性
,从而导致基础字段
易失性
。抱歉,您的答案没有回答问题,只有您的评论回答;-)。我认为,考虑到OPs编辑,他要求假设线程在执行
/*更多的代码时更改
标志
,是否保证
read2
会接受此更改。我认为没有理由保证。当然,
volatile
通常也没有人们想象的意义。就我个人而言,如果重要的话,我会查看
互锁
。另一种可能是使支持字段不稳定。所以你们仍然可以像internal一样使用相同的集合修饰符。那个么封装的volatile字段呢?私人易变布尔旗;还有一个属性标志{get{return Flag;},set{Flag=value;}}?非常有趣的一点,但在我的测试中,您的确切代码的发布版本没有锁定。在Visual Studio 2013的新控制台项目中运行,因此优化设置是默认设置。我知道它是否得到优化取决于实现,但我很难相信在使用(!Flag)而不是它的初始值时不会签入变量的实际值。特别是当编译器可以确定值确实发生了更改时。@ILIA BROUDNO:此示例取决于环境,但只要您有一台多核计算机,它在.Net版本之间应该是相当一致的。我刚刚在VS 2013、.Net 4.5四核Xeon上测试了这个,我仍然可以复制它。在构建项目时,请确保在项目属性中启用了“优化代码”。@Tudor:谢谢您的检查。在我这边-Visual Studio 2013.Net 4.5四核i5。已选中优化代码。没有锁定。