原子操作线程安全 - 我需要一个"镜像"原子读?

时间:2014-12-09 19:28:34

标签: c# .net multithreading atomic interlocked

下面的代码是否安全(单独考虑它)来自撕裂的读取?

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位环境的实现细节)。

但是,我还需要在读取端进行“镜像”操作吗?例如。我是否还有被阅读撕裂的风险,因为我没有原子地读取这个值?

我的预感是我不会,因为我认为另一个内存访问(例如读取)不能与任何其他原子操作同时发生,即使其他访问本身不是原子的。但我想要一些确认!

2 个答案:

答案 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 最终的值最终会为valueInterlocked.Exchange的两个保证{ {1}}给你),但是可能会破坏不同步的读访问权。