It is known that a reference takes 4 Bytes of memory in 32 bit processor and 8 Bytes - in 64 bit processor. So, processors guarantee that single reads from and writes to memory in increments of the natural word size of the machine will be carried out atomically. On the other hand there are 2 methods in Interlocked class:
public static int Exchange( ref int location1, int value )
and
public static T Exchange<T>( ref T location1, T value ) where T : class
So, the question is why Interlocked.Exchange is needed for Int32 and for reference types? Couldn't it be done safely by just using of simple assignment because it is atomic?
Interlock. Exchange returns the original value while performing an atomic operation. The whole point is to provide a locking mechanism. So it is actually two operations: read original value and set new value.
The methods of this class help protect against errors that can occur when the scheduler switches contexts while a thread is updating a variable that can be accessed by other threads, or when two threads are executing concurrently on separate processors.
The Interlocked class provides a number of static methods that perform atomic operations. These can generally be regarded as thread-safe.
Reference assignment is guaranteed to be atomic on all . NET platforms.
It is not only about atomicity. It is also about memory visibility. Variable can be stored in main memory or in CPU cache. If the variable is only stored in CPU cache it will not be visible to threads running on different CPU. Consider following example:
public class Test { private Int32 i = 5; public void ChangeUsingAssignment() { i = 10; } public void ChangeUsingInterlocked() { Interlocked.Exchange(ref i, 10); } public Int32 Read() { return Interlocked.CompareExchange(ref i, 0, 0); } }
Now if you call 'ChangeUsingAssignment' on one thread and 'Read' on another thread the return value may be 5, not 10. But if you call ChangeUsingInterlocked, 'Read' will return 10 as expected.
---------- ------------ ------------------- | CPU 1 | --> | CACHE 1 | --> | | ---------- ------------ | | | RAM | ---------- ------------ | | | CPU 2 | --> | CACHE 2 | --> | | ---------- ------------ -------------------
In the diagram above 'ChangeUsingAssignement' method may result in value 10 get 'stuck' in CACHE 2 and not make it to RAM. When CPU 1 later tries to read it, it will get the value from RAM where it is still 5. Using Interlocked instead of ordinary write will make sure that value 10 gets all the way to the RAM.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With