阅读双重不是线程安全的吗?

时间:2010-09-09 13:10:24

标签: .net thread-safety double

更新:我在Eric Lippert's answeranother question(他引用规范)中偶然发现了这一点:

  

其他类型的读写   包括long,ulong,double和   十进制,以及用户定义   类型,不保证是   原子。

好的,所以阅读double 不是原子。这意味着可以在读取中间修改该值,对吧?那么如何以原子方式读取double值?


我注意到long值的Interlocked.Read方法。这对我来说很有意义,因为读取64位值必须需要两个步骤,因此就像其他所有非原子动作一样受到竞争条件的影响。

Interlocked.Read值没有double,即使System.Double是64位值。

我在我的程序中看到一些奇怪的行为,我的GUI在文本框中显示double,而double也经常被其他线程更新,显示正确的值(在200.0)大多数的时间附近,然后随机显示一个错误值(如-0.08)偶尔

也许这是一个线程问题,或者可能是其他问题。但首先我想缩小可能性。那么:正在阅读double线程安全吗?

4 个答案:

答案 0 :(得分:17)

  

正在阅读双线程安全吗?

没有。正如规范所说

  

其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是原子的。

继续前进。

  

这意味着可以在读取中间修改该值,对吧?

  

那么如何以原子方式读取双值?

每次访问可变变量时都会锁定。

这是一个你没有问的问题,但经常被问到是你问题的后续问题:

  

使字段“易变”会使其读/写原子吗?

没有。制作double类型的volatile字段是不合法的。

答案 1 :(得分:9)

通常的方法:用锁控制访问。

答案 2 :(得分:6)

使用Interlocked.Exchange OR Interlocked.CompareExchange进行原子读取。

Interlocked.Exchange(ref somevariable, somevariable)

返回原始值。

如果您想避免使用compareExchange

Interlocked.CompareExchange(ref somevariable, somevalue, somevalue);

如果变量等于第三个参数,它将用第二个参数替换变量,并返回原始值。通过在两个点中使用相同的值(例如,零),它保证变量的值不会改变。

答案 3 :(得分:2)

CLR只允许4的变量对齐。这意味着long或double很可能跨越CPU缓存行的边界。这使得读取保证是非原子的。

这也是一个相当严重的性能问题,读取这样一个不良对齐的变量是慢3倍。除了黑客攻击之外,你无法真正做到这一点。