问题
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
回答1:
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.
来源:https://stackoverflow.com/questions/11555755/c-sharp-lazy-initialization-race-to-initialize