C # Lazy Initialization && Race-to-initialize?

After reading about LazyInitializer , so that it:

It offers a different initialization mode, which has several race streams for initialization.

here is an example:

 Expensive _expensive; public Expensive Expensive { get // Implement double-checked locking { LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive()); return _expensive; } } 

Question number 1

looking at: enter image description here

why does #A say it implements a double lock check? Is it just getting proeprty?

Question number 2

Is #B (lambda expression) thread safe?

Question number 3

So, I searched for 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: isnt the initialization race thread safe?

e / g / if 2 threads fall into:

enter image description here

expensive object will be created twice!

So 3 more questions

1) why does #A say it implements a double lock check? Is it just getting proeprty?

2) Is #B (lambda expression) thread safe?

3) isnt race to initialize is thread safe

+4
source share
1 answer

There are various EnsureInitialized overloads. Some accept a synclock object (which may be null and will be created by the EnsureInitialized method). Others do not have a synclock parameter as a parameter. All EnsureInitialized guarantees that if two (or more) different threads are called at the same time while the object is not initialized, the two threads will get a reference back 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 viewed by two threads will be the same.

The only problem is that new Expensive() could be called twice (once per thread, so in a multi-threaded race it could be called even more).

If you do not want this, use 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 new Expensive() will be called only once, for each possible combination of two (or more) threads.

+5
source

All Articles