Reputation: 148534
After reading about LazyInitializer
that it's :
It offers another mode of initialization that has multiple threads race to initialize.
here is a sample :
Expensive _expensive;
public Expensive Expensive
{
get // Implement double-checked locking
{
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
return _expensive;
}
}
Question #1
looking at :
why #A says its implements double-checking locking ? it is just a get proeprty ?
Question #2
Does #B (lambda expression) is thread safe ?
Question #3
So i searched about this "race-to-initialize" thing by looking at a sample:
volatile Expensive _expensive;
public Expensive Expensive
{
get
{
if (_expensive == null)
{
var instance = new Expensive();
Interlocked.CompareExchange (ref _expensive, instance, null);
}
return _expensive;
}
}
and then i thought about : isnt race to initialize is thread safe ?
e/g/ if 2 threads get into :
the expensive object will be created twice !
So again , 3 question
1)why #A says its implements double-checking locking ? it is just a get proeprty ?
2)Does #B (lambda expression) is thread safe ?
3)isnt race to initialize is thread safe
Upvotes: 4
Views: 2051
Reputation: 111870
There are various overloads of EnsureInitialized
. Some accepts a synclock
object (that can be null
and will be created by the EnsureInitialized
method). Others don't have a synclock
as a parameter. All the EnsureInitialized
guarantee that if called at the same time by two (or more) different threads while the object is uninitialized, the two threads will receive back a reference to the same object. So:
Expensive _expensive;
// On thread 1
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
// On thread 2
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
the _expensive
object that will be seen by the two threads will be the same.
The only problem is that new Expensive()
could be called twice (once per thread, so in a multi-thread race it could be called even more times.)
If you don't want it, use the synclock
overload:
Expensive _expensive;
object _sync = null;
bool _useless;
// On thread 1
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
// On thread 2
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
Now the new Expensive()
will be called only once, for every possible combination of the two (or more) threads running.
Upvotes: 5