以下代码是否安全(将其孤立地考虑)免受撕裂的读取?
private static double flopsErrorMargin = 0.01d;
public static double FlopsErrorMargin {
get {
double result = flopsErrorMargin;
Thread.MemoryBarrier();
return result;
}
set {
Interlocked.Exchange(ref flopsErrorMargin, value);
}
}
原子写入操作(Interlocked.Exchange()
)是必需的,因为不能保证在.NET平台上的单个操作中写入双精度(64位环境中的实现细节除外)。
但是,我是否还需要在读取端进行"镜像"操作? 例如,我是否仍然有被撕裂读取的风险,因为我没有原子读取值?
我的预感是我不会,因为我认为另一个内存访问(例如读取)不能与任何其他原子操作同时发生,即使其他访问本身不是原子的。但我想要一些确认!
不,撕裂的读取是可能的。假设您的字段访问正在读取数据并按Interlocked.Exchange
交错,那么其他 32 位将是 Exchange
的更新值,从而产生撕裂读取。
对于原子读取,您需要使用Interlocked.Read(在32位机器中)。
Read 方法在 64 位系统上是不必要的,因为 64 位读取 操作已经是原子的。在 32 位系统上,64 位读取 操作不是原子操作,除非使用读取执行
这也意味着撕裂的值是可能的。
您可以定义自己的原子Read
double
public static double Read(ref double location)
{
return Interlocked.CompareExchange(ref location, 0d, 0d);
}
这就是Interlocked.Read(long)
内部实施的方式。
我是否仍然有被撕裂读取的风险,因为我没有以原子方式读取值?
是的。 Interlocked.Exchange
的返回值不会被撕裂,flopsErrorMargin
最终得到的值将被value
(这是Interlocked.Exchange
给你的两个保证),但不同步的读取访问可能会被撕裂。