下面的代码是否安全(单独考虑它)来自撕裂的读取?
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平台上的单个操作中写入double(除了64位环境的实现细节)。
但是,我还需要在读取端进行“镜像”操作吗?例如。我是否还有被阅读撕裂的风险,因为我没有原子地读取这个值?
我的预感是我不会,因为我认为另一个内存访问(例如读取)不能与任何其他原子操作同时发生,即使其他访问本身不是原子的。但我想要一些确认!
答案 0 :(得分:3)
不,Torn读取是可能的。假设您的字段访问正在读取数据并在Interlocked.Exchange
中途交错,那么其他32位将是Exchange
的更新值,从而产生撕裂读取。
对于原子读取,您需要使用Interlocked.Read(在32位机器中)。
64位系统不需要Read方法,因为64位读取 操作已经是原子的。 在32位系统上,64位读取 除非使用Read
执行,否则操作不是原子操作
这也意味着可能存在撕裂的价值。
您可以为Read
定义自己的原子double
,如下所示
public static double Read(ref double location)
{
return Interlocked.CompareExchange(ref location, 0d, 0d);
}
这就是Interlocked.Read(long)
在内部实施的方式。
答案 1 :(得分:2)
我是否还有被阅读撕裂的风险,因为我没有原子地读取这个值?
是。 Interlocked.Exchange
的返回值不会被破坏,flopsErrorMargin
最终的值最终会为value
(Interlocked.Exchange
的两个保证{ {1}}给你),但是可能会破坏不同步的读访问权。