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

Fastest way to safely read contents of long[] whose elements are changed concurrently

当你有一个

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 的一半,以及 post- 增加一半,这可能会给出数组中不存在的值。

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

鉴于我不想使用任何锁定,Volatile.Read 变体是否是正确的选择?

C# 中没有 atomic 类型(您可能知道),只有 atomic 操作。

抖动and/or处理器可以决定重新排序指令,所以你假设你需要

  • 序列化 访问 lock
  • 使用 Interlocked class 进行写入(在某些情况下读取)
  • 声明变量 volatile(尽管它在 64 位类型上不可用,并且不适用于数组)
  • 或者在您的情况下,如果您不介意过时的值,请使用 Volatile.Read

回答你的问题,在没有看到你的代码或你是如何处理它的情况下,你的方法似乎是正确的解决方案

Volatile.Read Method

Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method

如果陈旧值对您来说不是问题,并且您只需要原子读取(不是有序读取),那么在 x64 上您可以只使用普通读取而不是 Volatile.Read。 它在 ARM 系统上可能是有益的,其中 volatile reads/writes 是相当重量级的,因为它们是用 DMB 实现的。

重要 根据 and that,您需要在 64 位模式下(构建和)运行 您的 .Net 程序才能工作:

if you are running C# code on a 64 bit operating system in a 64 bit version of the CLR then reads and writes of 64 bit doubles and long integers are also guaranteed to be atomic