Assignment to volatile variable in C#
c#, volatile
Solution
`volatile` is actually more related to caching (in registers etc); with `volatile` you know that that value is actually written-to/read-from memory immediately (which isn't actually always the case otherwise). This allows different threads to immediately see updates from each other. There are other subtle issues with instruction re-ordering, but that gets complex.
There are two meanings of "atomic" to consider here:
- is a single read atomic by itself / write atomic by itself (i.e. could another thread get two different halves of two `Double`s, yielding a number that never actually existed)
- is a read/write pair atomic/isolated together
The "by itself" depends on the size of the value; can it be updated in a single operation? The read/write pair is more to do with isolation - i.e. preventing lost updates.
In your example, it is possible for two threads to read the same `_lastValue`, both do the calculations, and then (separately) update `_lastValue`. One of those updates is going to get lost. In reality, I expect you want a `lock` over the duration of the read/write process.
Problem
My understanding of C# says (thanks to Jeff Richter & Jon Skeet) that assignment is "atomic". What is not is when we mix reads & writes (increment/decrement) and hence we need to use methods on the Interlocked. If have only Read & assign would both the operations be atomic? ` ``` public class Xyz { private volatile int _lastValue; private IList<int> AvailableValues { get; set; } private object syncRoot = new object(); private Random random = new Random(); //Accessible by multiple threads public int GetNextValue() //and return last value once store is exhausted { //... var count = 0; var returnValue = 0; lock (syncRoot) { count = AvailableValues.Count; } if (count == 0) { //Read... without locking... potential multiple reads returnValue = _lastValue; } else { var toReturn = random.Next(0, count); lock (syncRoot) { returnValue = AvailableValues[toReturn]; AvailableValues.RemoveAt(toReturn); } //potential multiple writes... last writer wins _lastValue = returnValue; } return returnValue; } ``` `