此问题之前已被问过,但我仍然完全不理解,所以这里就是这样。
如果我有一个带有属性的类(一个不可为空的double或int) - 我可以读取和写入多个线程的属性吗?
我已经读过某个地方,因为双精度数为64字节,所以可以在一个线程上读取一个double属性,而不是在另一个线程上写入。这将导致读取线程返回既不是原始值也不是新写入值的值。
什么时候会发生这种情况?也可以使用整数? 64位和32位应用程序都会发生这种情况吗?
我无法在控制台中复制这种情况
答案 0 :(得分:3)
如果我有一个带有属性的类(一个不可为空的double或int) - 我可以用多个theads读写这个属性吗?
我认为你的意思是“没有任何同步”。
double
和long
的大小均为64 位(8字节),并且不保证以原子方式写入。因此,如果您从具有字节模式ABCD EFGH的值移动到具有字节模式MNOP QRST的值,您可能可能最终看到(来自不同的线程)ABCD QRST或MNOP EFGH。
使用大小为32位或更低的正确对齐值,可保证原子性。 (我不记得看到任何保证值将正确对齐,但我相信它们是默认情况下,除非你通过属性强制特定布局。)C#4规范甚至没有提到对齐在第5.5节中涉及原子性:
以下数据类型的读写是原子的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型。此外,在先前列表中具有基础类型的枚举类型的读取和写入也是原子的。其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是原子的。除了为此目的而设计的库函数之外,不保证原子读 - 修改 - 写,例如在递增或递减的情况下。
此外,原子性与波动性不同 - 因此,如果不采取任何额外的谨慎措施,从一个线程读取可能不会“看到”来自不同线程的写入。
答案 1 :(得分:1)
这些操作不是原子操作,这就是Interlocked
类首先存在的原因,使用Increment(Int32)
和Increment(Int64)
等方法。
为了确保线程安全,您应该至少使用此类,如果不是更复杂的锁定(使用ReaderWriterLockSlim
,例如,如果您想要同步对属性组的访问)。