In the below code, I populate the contents of the dictionary then assign it to Data
. As such, my mental expectation is that Data
will contain either null
or a Dictionary
with two elements in it.
But is that a valid expectation?
I know that writes can be reordered. And the simple fix, presumably, would be to add volatile
to Data
. But is that needed? Or is the original code guaranteed "safe" (safe in the sense that I can be 100% confident that Data
will never contain a Dictionary that has < 2 elements in it).
using System;
using System.Collections.Generic;
public class Program
{
public static Dictionary<int, int> Data = null;
public static void Main()
{
var bob = new Dictionary<int, int>();
bob.Add(1, 1);
bob.Add(2, 2);
Data = bob;
// Note that there be no further mutation of `bob` or `Data` after this.
// Imagine there is a separate thread reading the contents of `Data`
}
}
I am not even super confident of the volatile
suggestion in light of the wisdom of Skeet and Lippert ("Frankly, I discourage you from ever making a volatile field.").
I know that writes can be reordered. And the simple fix, presumably, would be to add
volatile
toData
. But is that needed?
Yes, it is definitely needed. Without the volatile
the compiler/Jitter/processor might reorder the instructions of the program in a way that the Data
might point for a brief period of time to a partially initialized Dictionary<K,V>
object. The behavior of a partially initialized object is undefined. It might contain less than 2 elements, it might throw exceptions, whatever. Or it might work correctly because no reordering actually happened. If you want to be responsible and leave nothing to chance, you should definitely declare the Data
as volatile
, so that any possibility of reordering is prevented.
A detailed explanation about why the volatile
is needed in lazy-initialization scenarios, can be found in this 2013 article by Igor Ostrovsky: