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?