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。已选中优化代码。没有锁定。