假设我有一个非易失性的int字段,以及一个它Interlocked.Increment的线程.另一个线程可以直接安全地读取它,还是读取也需要互锁?
我以前认为我必须使用互锁读取来保证我看到当前值,因为毕竟,该字段不是易失性的.我一直在Interlocked.CompareExchange(int, 0, 0)努力实现这一目标.
但是,我偶然发现了这个答案,这表明实际的普通读取总会看到Interlocked.Incremented值的当前版本,并且因为int读取已经是原子的,所以不需要做任何特殊的事情.我还发现了Microsoft拒绝Interlocked.Read(ref int)请求的请求,进一步表明这完全是多余的.
那么我能真正安全地阅读这样一个int领域的最新价值Interlocked吗?
从规范10.5.3挥发性字段:
volatile字段的类型必须是以下之一:
引用类型.
类型byte,sbyte,short,ushort,int,uint,char,float,bool,System.IntPtr或System.UIntPtr.
具有枚举基类型byte,sbyte,short,ushort,int或uint的枚举类型.
首先,我想确认我的理解是正确的:我猜上面的类型可以是volatile,因为它们在内存中存储为4字节单元(因为它的地址对于引用类型),这保证了读/写操作是原子的.double/long/etc类型不能是volatile,因为它们不是原子读/写,因为它们在内存中超过4个字节.我的理解是否正确?
第二,如果第一个猜测是正确的,为什么用户定义的结构只有一个int字段(或类似的东西,4个字节就可以)不能是易失性的?理论上它是原子的吗?或者仅仅是因为所有用户定义的结构(可能超过4个字节)不允许设计的易失性?
因为只有引用类型和一些原语(包括float,但不是double,我不确定原因,我很高兴听到原因)可以声明为volatile,如果我在类中包装double然后声明它作为volatile(如下所示),double属性是'read write'线程安全,就像任何其他volatile一样,还是我还应该看看锁定?
public class MyThreadedClass
{
volatile VolatileDouble voldub;
}
public class VolatileDouble
{
public double Double { get; set; }
}
Run Code Online (Sandbox Code Playgroud) 我可以想到一些使用案例,让DateTime对象成为原子非常有用.从语言设计的角度来看,有什么优势可以使DateTime不稳定?