Suppose you have a property public Foo Bar { get; } that you want to lazily initialize. One such approach might be to use the Interlocked class, which guarantees atomicity for certain sequences of operations (e.g. incrementing, adding, compare-exchange). You could do this:
private Foo _bar;
public Foo Bar
{
get
{
// Initial check, necessary so we don't call new Foo() every time when invoking the method
if (_bar == null)
{
// In the unlikely case 2 threads come in here
// at the same time, new Foo() will simply be called
// twice, but only one of them will be set to _bar
Interlocked.CompareExchange(ref _bar, new Foo(), null);
}
return _bar;
}
}
There are many places that demonstrate this approach to lazy initialization, e.g. this blog and places in the .NET Framework itself.
My question is, shouldn't the read from _bar be volatile? For example Thread 1 could have called CompareExchange, setting the value of _bar, but that change wouldn't be visible to Thread 2 since (if I understand this question correctly) it may have cached the value of _bar as null, and it may end up calling Interlocked.CompareExchange again, despite the fact that Thread 1 already set _bar. So shouldn't _bar be marked volatile, to prevent this from happening?
In short, is this approach or this approach to lazy initialization correct? Why is Volatile.Read (which has the same effect as marking a variable volatile and reading from it) used in one case, but not the other?
edit TL;DR: If one thread updates the value of a field via Interlocked.CompareExchange, will that updated value be immediately visible to other threads performing non-volatile reads of the field?