当你有一个
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
变体是正确的选择吗?
答案 0 :(得分:1)
在C#中,没有像 atomic 这样的东西(您可能知道),只有 atomic 操作。
抖动和/或处理器可以决定对指令进行重新排序,因此假设您需要
是正确的。lock
Interlocked
类进行写入(在某些情况下为读取)volatile
(尽管在64位类型上不可用,并且不适用于数组)Volatile.Read
。要回答您的问题,并且看不到代码或如何执行此操作,您的方法似乎是正确的解决方案
读取字段的值。在需要它的系统上,插入一个 内存屏障,可防止处理器重新排序内存 操作如下:如果在此方法之后出现读或写 代码,处理器无法在使用此方法之前将其移动
答案 1 :(得分:1)
如果过时的值对您来说不是问题,并且您只需要原子读取(而不是有序读取),那么在x64上,您可以使用普通读取而不是Volatile.Read
。
在使用DMB实现易失性读写的ARM系统上,这可能是有益的。
重要 根据{{3}}和this的说法,您需要以64位模式(生成并)运行.Net程序,这样才能正常工作:
如果要在64位操作系统上以64位运行C#代码 版本的CLR然后读取和写入64位double和long 整数也保证是原子的