我和我的同事正在就使用 C# .NET 4.0 在英特尔架构上读取 double 的原子性争论不休。他争论说我们应该使用 Interlocked.Exchange
方法来写入 double
,但只读取 double 值(在其他线程中)保证是原子的。我的论点是 .NET 不保证这种原子性,但他的论点是在 Intel 架构上这是有保证的(可能不在 AMD 、 SPARC 等上)。
是否有任何英特尔和 .NET 专家对此有一些看法?
Reader 可以读取陈旧的(以前的)值,但不能读取不正确的值(写入前后的部分读取给出垃圾值)。
最佳答案
My colleague and I are having an argument on atomicity of reading a double on an Intel architecture using C# .NET 4.0.
Intel 保证当与 8 字节边界对齐时,8 字节 double 值在读取和写入时是原子的。
C# 不保证 double 值与 8 字节边界对齐。
He is arguing that we should use
Interlocked.Exchange
method for writing into a double, but just reading the double value (in some other thread) is guaranteed to be atomic.
您的同事没有仔细考虑这个问题。互锁操作只是原子相对于其他互锁操作。 某些时候使用互锁操作没有任何意义;这就像在说,通过十字路口向北行驶的车辆不必遵守红绿灯,因为通过十字路口向西行驶的车辆确实遵守红绿灯。每个人都必须遵守灯光,以免发生碰撞;你不能只做一半。
My argument is that .NET doesn't guarantee this atomicity, but his argument is that on an Intel architecture this is guaranteed (maybe not on AMD, SPARC, etc.).
看,假设这个论点是正确的,但事实并非如此。我们应该得出的结论是,通过错误操作节省的几纳秒是否值得冒这个风险?忘记互锁。 每次都进行完全锁定。跨线程共享内存时,您唯一不应该完全锁定的情况是当您有一个已证明的性能问题时,该问题实际上是由于锁定的 12 纳秒开销造成的。那是当 12 纳秒的惩罚是您程序中最慢的事情并且仍然 Not Acceptable 时,那一天您应该考虑使用低锁解决方案。您的程序中最慢的事情是否占用了 12 纳秒的非竞争锁?不?然后停止争论,花宝贵的时间让程序中需要 超过 12 纳秒的部分更快。
Reader is OK to read a stale (previous) value, but not incorrect value (partial read before and after write giving a garbage value).
不要将原子性与波动性混为一谈。
互锁操作和锁定语句都将构成一个内存屏障,以确保读取或发布最新值。不需要普通的非 volatile 读取或写入;如果碰巧这样做,那你就走运了。
如果您对这些问题感兴趣,我偶尔会被问到一个相关问题,那就是在什么情况下可以取消对整数访问的锁定。我关于该主题的文章是:
关于c# - 英特尔架构上的双读原子吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24731791/