Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Array.Copy maintain the guarantee about atomic reads and writes on a per element basis?

Tags:

c#

.net

atomic

C# ensures that certain types always have atomic reads and writes. Do I have those same assurances when calling Array.Copy on two arrays of those types? Is each element atomically read and written? I browsed some of the source code but did not come away with a solid answer.

For example, if I rolled my own code for copying two arrays...

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

... and called the Copy<int> variant, this guarantees that each element is atomically read from source and atomically written to destination because C# promises that int reads and writes are atomic. I'm simply asking if Array.Copy maintains that guarantee (as opposed to, say, using its own specialized memory block copy routine that possibly breaks this guarantee).

like image 798
TheBuzzSaw Avatar asked Jul 14 '18 20:07

TheBuzzSaw


People also ask

Is an array Atomic?

The array write itself is atomic, but when you include the lookup (dereferencing a[1] ) there are two separate operations involved.

What is array copy in c#?

Copy(Array, Array, Int64) Copies a range of elements from an Array starting at the first element and pastes them into another Array starting at the first element. The length is specified as a 64-bit integer. public: static void Copy(Array ^ sourceArray, Array ^ destinationArray, long length); C# Copy.


1 Answers

Array.Copy() tries to make the copy efficient by using the memmove() CRT function, a raw memory-to-memory copy without regard for the actual type stored in the array. It can be substantially more efficient if the array element type is smaller than the natural processor word size.

So you need to know whether memmove() can provide the atomicity guarantee. That is an tricky question that the CLR programmer answered unambiguously. Atomiticy is an essential trait for object references, the garbage collector cannot operate correctly when it can't update those references atomically. So the programmer special-cases this in the CLR code, the comment he provided tells you what you want to know (edited to fit):

// 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.

That's a very pessimistic view on life. But clearly no, you can't assume Array.Copy() is atomic when the CLR author did not make this assumption.


Practical consideration do perhaps need to prevail. On reasonably common architectures, x86 and x64 have a memmove() implementation that don't make the CLR memory model guarantees worse, they copy 4 or 8 aligned bytes at a time. And practically the for-loop in the generic code substitute is not guaranteed to be atomic since T is not guaranteed to be.

Most practical is that you ought not have to ask the question. Atomicity only matters when you have another thread that is accessing the arrays without any synchronization. Writes to the source array or reads from the destination array. That is however a guaranteed threading race. Writes to the source array are worst, the copy has an arbitrary mix of old and new data. Reads from the destination array randomly produce stale data, like a threading bug normally does. You have to be quite courageous to risk this kind of code.

like image 190
Hans Passant Avatar answered Oct 13 '22 00:10

Hans Passant