问题
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?
回答1:
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
回答2:
There are no such thing as an atomic type in C# (as you probably know), there are only atomic operations.
The Jitter and/or Processor can decide to reorder instructions, so you are correct in assuming you either need to
- Serialize access with
lock
- Use the
Interlocked
class for writes (and in some cases reads) - Declare the variable
volatile
(though its not available on a 64 bit types, and doesn't apply to an array) - Or in your situation use
Volatile.Read
if you don't mind stale values.
To answer your question, and without seeing your code or how you are threading this, your approach seems like the right solution
Volatile.Read Method
Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method
来源:https://stackoverflow.com/questions/52939887/fastest-way-to-safely-read-contents-of-long-whose-elements-are-changed-concurr