代码之家  ›  专栏  ›  技术社区  ›  Evgeniy Berezovsky

安全读取long[]的内容的最快方法,其元素同时更改

  •  3
  • Evgeniy Berezovsky  · 技术社区  · 7 年前

    当你有一个

    long[] myArray = new long[256];
    

    其项由多个线程使用

    Interlocked.Increment(ref myArray[x])
    

    当然不可能得到 myArray 在某个时间点上,由于有非锁定的写操作同时进行,所以我不想尝试获取。

    所以我真的必须 Volatile.Read 像这样的每一个元素在过去的某个时刻得到所有值的副本?

    long[] copy = new long[256];
    for (int i = 0; i < 256; i++)
        copy[i] = Volatile.Read(ref myArray[i]);
    

    由于我对某个时间点的快照不感兴趣,过时的值不是问题,但由于64位非易失性读取不是原子的,我担心下面的代码可能会给我一个长的前半个增量,一个后半个增量,这可能会给出一个数组中从未存在过的值。

    long[] copy = new long[256];
    for (int i = 0; i < 256; i++)
        copy[i] = myArray[i];
    

    所以 易失性。读取 如果我不想使用任何锁定,请更改正确的选择?

    2 回复  |  直到 7 年前
        1
  •  1
  •   Evgeniy Berezovsky    7 年前

    如果过时的值对您来说不是问题,您所需要的只是原子读取(不是有序的),那么在x64上,您可以只使用普通读取而不是 Volatile.Read . 在使用DMB实现的易失性读/写相当繁重的ARM系统上,这可能是有益的。

    重要的 根据 this that ,您需要(生成并)以64位模式运行.NET程序才能正常工作:

    如果您在64位操作系统上以64位运行C代码 然后,clr版本读取和写入64位双精度和长 整数也保证是原子的

        2
  •  1
  •   TheGeneral    7 年前

    世上没有 原子的 输入c(如您所知),只有 原子的 操作。

    这个 抖动 和/或 处理器 可以决定对指令重新排序,因此您可以正确地假设您需要

    • 序列化 使用 lock
    • 使用 Interlocked 类进行写入(在某些情况下进行读取)
    • 声明变量 volatile (尽管它不适用于64位类型,也不适用于数组)
    • 或者在你的情况下使用 Volatile.Read 如果你不介意陈旧的价值观。

    要回答您的问题,并且在看不到您的代码或如何处理这些代码的情况下,您的方法似乎是正确的解决方案

    Volatile.Read Method

    读取字段的值。在需要它的系统上,插入 防止处理器重新排序内存的内存屏障 操作如下:如果在 代码,处理器无法在此方法之前移动它