代码之家  ›  专栏  ›  技术社区  ›  Dan Tao

读取双线程是否不安全?

  •  15
  • Dan Tao  · 技术社区  · 14 年前

    更新 我刚刚在 Eric Lippert's answer another question (他在引用规范):

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

    好吧,那么读一篇 double 原子的这意味着该值可以在读取过程中修改,对吗?那么怎么读A 双重的 原子价值?


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

    但是没有 联锁读取 对于 双重的 价值观,即使 System.Double 是64位值。

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

    可能这是线程问题,也可能是其他问题。但首先,我想缩小可能性。那么:是读A吗? 双重的 线程安全吗?

    4 回复  |  直到 10 年前
        1
  •  10
  •   Marcelo Cantos    14 年前

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

        2
  •  17
  •   Eric Lippert    14 年前

    读双线程安全吗?

    不,如规范所述

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

    继续前进。

    这意味着该值可以在读取过程中修改,对吗?

    对。

    那么如何原子地读取一个双值呢?

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

    一个你没有问过的问题,但经常被问到作为你问题的后续行动:

    使一个字段“易失性”会使它的读/写成为原子的吗?

    不可以。将不稳定字段设为double类型是不合法的。

        3
  •  5
  •   Sami Perttu pavy bez    10 年前

    使用 Interlocked.Exchange Interlocked.CompareExchange 对于原子,这样读。

    Interlocked.Exchange(ref somevariable, somevariable)

    它返回原始值。

    如果你想避免写作使用 compareExchange .

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

    如果变量等于第三个参数,则它将用第二个参数替换该变量,并返回原始值。通过在两个点上使用相同的值(例如,零),可以确保变量的值不会发生更改。

        4
  •  2
  •   Hans Passant    14 年前

    clr只保证变量对齐为4。这意味着长时间或双时间跨越CPU缓存线的边界是完全可能的。这使得读保证是非原子的。

    这也是一个相当严重的性能问题,读取这样一个排列不良的变量的速度要慢3倍以上。除了攻击指针,你真的无能为力。