Search code examples
c#.netmultithreadingvolatileinterlocked

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


When you have a

long[] myArray = new long[256];

whose items are changed by multiple threads using

Interlocked.Increment(ref myArray[x])

it sure won't be possible to get a snapshot of myArray at one point in time, as there are non-locked writes going on concurrently, so I'm not trying to get that.

So do I really have to Volatile.Read of every single element like this to get a copy of all values at some point in the past?

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

As I'm not interested in a snapshot at one point in time, stale values are not a problem, but as 64-bit non-volatile reads are not atomic, I fear that the following may give me a pre-increment half of a long, and a post-increment half, which may give a value that never existed in the array.

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

So is the Volatile.Read variant the proper choice, given I don't want to use any locking?


Solution

  • If stale values is not an issue for you and all you need is atomic read (not ordered one) then on x64 you can just use plain read instead of Volatile.Read. It can be beneficial on on ARM systems where volatile reads/writes are fairly heavyweight as they are implemented with DMB.

    Important According to this and that, you need to (build and) run your .Net program in 64-bit mode for this to work:

    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