E
E
Exvel2016-12-09 17:53:32
.NET
Exvel, 2016-12-09 17:53:32

[.NET] Is getting/writing an array element by index an atomic operation?

In various .NET collections, indexers are properties, and it is clear that getting or setting an element by index is not an atomic operation in this case.
I'm wondering if there is an exception for arrays in this case?
Can such an operation have the right to life, or can the access through the indexer and the installation back be interrupted by a context switch?

int original = Interlocked.CompareExchange(ref array[2], 5, 3);
The reference to the array does not change, only the values ​​of the elements in the cells are changed by different threads.
Update:
The generated IL seems to treat the array variable like any other variable:
IL_0017: ldloc.0      // 'array'
IL_0018: ldc.i4.2     
IL_0019: ldelema      [mscorlib]System.Int32
IL_001e: ldc.i4.5     
IL_001f: ldc.i4.3     
IL_0020: call         int32 [mscorlib]System.Threading.Interlocked::CompareExchange(int32&, int32, int32)
IL_0025: pop
I'm still inclined to believe that the operation is atomic, but it's better to get the opinion of a knowledgeable person.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
MrDywar Pichugin, 2016-12-09
@Dywar

IL code is only half the battle.
The version of the VM and the bitness of the assembly are important, debug / release mode.
Use windbg, there you can see the code of the method that will be executed by the CPU.
I'm not answering the question, but giving food for thought.
Book - "Goldstein S. - Optimization of applications on the .NET platform - 2014".
Excerpts from the book:
"Writing a 32-bit integer is always done atomically. This means that if a processor writes the value 0xdeadbeef to a memory location previously initialized to zero, another processor will never receive the partially modified value in that location."
"Unfortunately, the same cannot be said for larger data; for example, even on a 64-bit processor, a 20-byte write operation is not atomic and cannot be atomic."
"Whenever an operation on a region of memory requires the execution of several instructions, a synchronization problem immediately arises. For example, the operation ++i (where i is a variable on the stack of type int) is usually translated into a sequence of three machine instructions:
   

 mov еах, dword ptr [ebp-64] ; скопировать со стека в регистр
    inc еах ;                                        увеличить значение в регистре
    mov dword ptr [ebp-64], еах ; скопировать из регистра на стек

Each of these instructions is executed atomically, but without additional synchronization, there is a chance that two processors will execute parts of this sequence of instructions concurrently. This is a "race condition".
All processor families that Windows can run on support a hardware synchronization primitive called Compare-And-Swap (CAS).
In Intel x86 processors, this primitive is implemented as a LOCK cmpxchg instruction. In the .NET Framework, the CAS primitive is implemented as a set of overloaded Interlocked.CompareExchange methods.
// Код на С#:
    int n = . . .;
    if (Interlocked.CompareExchange(ref n, 1, 0) = 0) ( // заменить 0 на 1
      // ...выполнить некоторые операции
    }
    // инструкции на языке ассемблера х8б:
    mov еах, 0 ;
    mov edx, 1 ;
    lock cmpxchg dword ptr [ebp-64], edx ;
    test eax, eax ;
    i
    jnz not__taken
    // ... выполнить некоторые операции
    not_taken:

"

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question