2012-07-19 102 views
4

reading经过约LazyInitializer,它是:C#懒惰初始化&&比赛初始化?

它提供了具有多线程 比赛初始化初始化的另一种方式。

这里是一个示例:

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

问题#1

看: enter image description here

为什么#A说,它的工具双重检查锁定?它只是一个获得成功?

问题2

不会#B(lambda表达式)是线程安全的?

问题#3

于是我去搜索这个通过看样品“比赛到初始化”件事:

volatile Expensive _expensive; 
public Expensive Expensive 
{ 
    get 
    { 
    if (_expensive == null) 
    { 
     var instance = new Expensive(); 
     Interlocked.CompareExchange (ref _expensive, instance, null); 
    } 
    return _expensive; 
    } 
} 

,然后我想到了:心不是比赛初始化是线程安全的?

E/G/2个,如果线程进入:

enter image description here

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

如此反复,3问题

1)为什么说#A的工具双重检查锁定?它只是一个获得成功?

2)#B(l​​ambda表达式)是线程安全的吗?

3)心不是比赛来初始化是线程安全的

+1

评论“// Implement ...”听起来更像是一个未来计划,我会说 – Qnan 2012-07-19 07:23:55

回答

5

还有的EnsureInitialized各种重载。有些接受synclock对象(可以是null并将由EnsureInitialized方法创建)。其他人没有synclock作为参数。所有的EnsureInitialized保证,如果在未初始化对象的同时由两个(或更多)不同的线程调用,则两个线程将接收对同一对象的引用。所以:

Expensive _expensive; 

// On thread 1 
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive()); 

// On thread 2 
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive()); 

这个_expensive会被两个线程看到的对象是一样的。

唯一的问题是new Expensive()可能会被调用两次(每个线程一次,所以在多线程竞争中它可能会被调用更多次。)

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

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

现在new Expensive()将只调用一次,用于运行两个(或多个)线程的每一个可能的组合。

+0

确实_race-to-initialize_是_race condition_吗? (这是相同的术语?) – 2012-07-19 08:03:38

+0

@RoyiNamir它取决于如果初始化有副作用:-)如果它没有副作用,那么它不是一个真正的种族,因为(取自维基)'A竞争状况或种族危害是电子系统或过程中的缺陷,因此过程的输出或结果出乎意料地并且严格依赖于其他事件的顺序或时间。“无副作用=>输出没有差异(显然非常资源的高度利用可以被归类为副作用)。如果方法是'新列表()',那么没有任何问题。如果它是“将100美元转让给某人”,那么就是。 – xanatos 2012-07-19 08:06:36

+0

那么我使用'LazyInitializer.EnsureInitialized'(没有syncobj)有什么好处?我可以使用'懒惰 _expensive = new懒惰 (()=> new Expensive(),true);'这也是线程sagfe &&懒惰... – 2012-07-19 08:16:29