C#延迟初始化和放大器;&安培;比赛到初始化?安培、初始化、放大器

2023-09-03 17:10:45 作者:下一個街角

在阅读有关 LazyInitializer ,它是:

它提供的初始化的另一种方式,有多个线程   比赛进行初始化。

It offers another mode of initialization that has multiple threads race to initialize.

下面是一个例子:

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

问题1

看:

looking at :

为什么#A说,它的器具双重检查锁定?它只是一个get proeprty?

why #A says its implements double-checking locking ? it is just a get proeprty ?

问题#2

请问#B(拉姆达EX pression)是线程安全的?

Does #B (lambda expression) is thread safe ?

问题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 /克/如果2个线程进入:

e/g/ if 2 threads get into :

昂贵的对象将被创建两次!

the expensive object will be created twice !

所以,再一次,3个问题

So again , 3 question

1)为什么#A说,它的器具双重检查锁定?它只是一个get proeprty?

1)why #A says its implements double-checking locking ? it is just a get proeprty ?

2)是否#B(拉姆达EX pression)是线程安全的?

2)Does #B (lambda expression) is thread safe ?

3)心不是种族初始化是线程安全的。

3)isnt race to initialize is thread safe

推荐答案

EnsureInitialized 的各种重载。一些接受的SyncLock 对象(可以是,并将由 EnsureInitialized 法)。人无我有一个的SyncLock 作为参数。所有 EnsureInitialized 的保证,如果被称为在同一时间两个(或更多),而对象是未初始化的不同的线程,这两个线程将收到回一个引用同一个对象。所以:

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());

_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.)

如果你不想要它,使用的SyncLock 过载:

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.