Array.Copy是否保持每个元素的原子读写保证?

The*_*Saw 5 .net c# atomic

C#确保某些类型始终具有原子读取和写入.在调用Array.Copy这两种类型的数组时,我是否有同样的保证?每个元素是否以原子方式读写?我浏览了一些源代码,但没有得到一个可靠的答案.

例如,如果我推出自己的代码来复制两个数组......

static void Copy<T>(T[] source, T[] destination, int length)
{
    for (int i = 0; i < length; ++i)
        destination[i] = source[i];
}
Run Code Online (Sandbox Code Playgroud)

...并且调用了Copy<int>变体,这保证了每个元素都是从原子上读取source并原子写入的,destination因为C#承诺int读取和写入都是原子的.我只是问是否Array.Copy保持这种保证(相反,使用它自己的专用内存块复制例程,可能会破坏这种保证).

Han*_*ant 9

Array.Copy()尝试使用memmove()CRT函数使副本高效,CRT函数是一个原始的内存到内存副本,而不考虑存储在数组中的实际类型.如果阵列元素类型小于自然处理器字大小,则可以显着更高效.

所以你需要知道memmove()是否可以提供原子性保证.这是一个棘手的问题,CLR程序员毫不含糊地回答.Atomiticy是对象引用的基本特征,当垃圾收集器无法以原子方式更新这些引用时,它无法正常运行.所以程序员在CLR代码中特殊情况下,他提供评论告诉你你想知道什么(编辑适合):

// The CRT version of memmove does not always guarantee that updates of 
// aligned fields stay atomic (e.g. it is using "rep movsb" in some cases).
// Type safety guarantees and background GC scanning requires object 
// references in GC heap to be updated atomically.
Run Code Online (Sandbox Code Playgroud)

这是对生活的一种非常悲观的看法.但显然不是,当CLR作者没有做出这个假设时,你不能假设Array.Copy()是原子的.


实际考虑也许需要占上风.在相当常见的体系结构上,x86和x64有一个memmove()实现,它不会使CLR内存模型保证更差,它们一次复制4或8个对齐的字节.实际上,通用代码替换中的for循环不能保证是原子的,因为不能保证T.

最实际的是你不应该问这个问题.只有在没有任何同步的情况下访问阵列的另一个线程时,原子性才有意义.写入源数组或从目标数组读取.然而,这是一个有保障的线程竞赛.写入源数组是最糟糕的,副本具有新旧数据的任意组合.从目标数组读取随机生成过时数据,就像通常的线程错误一样.你必须非常勇敢地冒这种代码.