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

时间:2018-10-23 01:32:45

标签: c# .net multithreading volatile interlocked

当你有一个

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];

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

2 个答案:

答案 0 :(得分:1)

在C#中,没有像 atomic 这样的东西(您可能知道),只有 atomic 操作。

抖动和/或处理器可以决定对指令进行重新排序,因此假设您需要

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

要回答您的问题,并且看不到代码或如何执行此操作,您的方法似乎是正确的解决方案

Volatile.Read Method

  

读取字段的值。在需要它的系统上,插入一个   内存屏障,可防止处理器重新排序内存   操作如下:如果在此方法之后出现读或写   代码,处理器无法在使用此方法之前将其移动

答案 1 :(得分:1)

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

重要 根据{{​​3}}和this的说法,您需要以64位模式(生成并)运行.Net程序,这样才能正常工作:

  

如果要在64位操作系统上以64位运行C#代码   版本的CLR然后读取和写入64位double和long   整数也保证是原子的