C#懒惰<;T>&;竞相初始化?

C#懒惰<;T>&;竞相初始化?,c#,.net,multithreading,.net-4.0,lazy-evaluation,C#,.net,Multithreading,.net 4.0,Lazy Evaluation,(问了之后,我还有一个问题。) Lazy的整个思想(AFAIK)是仅在需要时创建对象。 为什么?因为这是昂贵的创造 我最不希望的事情是昂贵的对象将被创建>1次 我不在乎是否许多线程最终会产生相同的引用。我只是不希望他们创建多个实例 所以Lazyinitializer通过syncLock处理这个问题: LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive()

(问了之后,我还有一个问题。)

Lazy
的整个思想(AFAIK)是仅在需要时创建对象。 为什么?因为这是昂贵的创造

我最不希望的事情是
昂贵的
对象将被创建
>1次

我不在乎是否许多线程最终会产生相同的引用。我只是不希望他们创建多个实例

所以
Lazyinitializer
通过
syncLock
处理这个问题:

LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
但是
Lazy
如何处理呢? 我已在msdn中搜索,但找不到任何
syncLock
重载


我遗漏了什么?

听起来你想看看构造函数重载,它采用了
LazyThreadSafetyMode

Lazy<T> lazy = new Lazy<T>(() => new T, LazyThreadSafetyMode.ExecutionAndPublication);
Lazy-Lazy=new-Lazy(()=>newt,LazyThreadSafetyMode.ExecutionAndPublication);

Lazy
基本上是一个用户友好的
LazyInitializer
版本,单线程或多线程init的精确实现隐藏在该枚举后面。

您是否在问Lazy在内部是如何工作的?Lazy保证只创建一个,如下所示:

默认情况下,惰性对象是线程安全的。也就是说,如果构造函数 不指定线程安全的类型,它的惰性对象 创建线程安全的。在多线程场景中,第一个线程 要访问线程安全惰性对象的Value属性,请初始化 它用于所有线程上的所有后续访问,并且所有线程共享 同样的数据。因此,初始化哪个线程并不重要 对象和种族条件都是良性的

如果您实际上是在问它内部是如何工作的,那么它似乎在使用某种类型的

        object obj = Volatile.Read<object>(ref this.m_threadSafeObj);
        bool flag = false;
        try
        {
            if (obj != Lazy<T>.ALREADY_INVOKED_SENTINEL)
            {
                Monitor.Enter(obj, ref flag);
            }
            if (this.m_boxed == null)
            {
                boxed = this.CreateValue();
                this.m_boxed = boxed;
                Volatile.Write<object>(ref this.m_threadSafeObj, Lazy<T>.ALREADY_INVOKED_SENTINEL);
            }
            else
            {
                boxed = (this.m_boxed as Lazy<T>.Boxed);
                if (boxed == null)
                {
                    Lazy<T>.LazyInternalExceptionHolder lazyInternalExceptionHolder = this.m_boxed as Lazy<T>.LazyInternalExceptionHolder;
                    lazyInternalExceptionHolder.m_edi.Throw();
                }
            }
        }
        finally
        {
            if (flag)
            {
                Monitor.Exit(obj);
            }
        }
objectobj=Volatile.Read(参考this.m_threadSafeObj);
布尔标志=假;
尝试
{
if(obj!=懒惰。已调用\u哨兵)
{
监视器输入(obj,ref标志);
}
if(this.m_boxed==null)
{
boxed=this.CreateValue();
this.m_boxed=已装箱;
Volatile.Write(参考this.m_threadSafeObj,Lazy.ready_调用了_SENTINEL);
}
其他的
{
boxed=(this.m_被装箱为Lazy.boxed);
如果(已装箱==null)
{
Lazy.LazyInternalExceptionHolder LazyInternalExceptionHolder=此.m_装箱为Lazy.LazyInternalExceptionHolder;
lazyInternalExceptionHolder.m_edi.Throw();
}
}
}
最后
{
国际单项体育联合会(旗)
{
监控出口(obj);
}
}

注意监视器。输入和监视器。退出调用。

wt*?像在LazyInitializer中创建的那样添加syncobj有那么难吗?
Lazy
with
ExecutionAndPublication
相当于
LazyInitializer
with
syncLock
。你只会得到一个实例。@Royi通常不是关于某件事是否“困难”(尽管这可能是一个因素),而是:它是否需要?它有用吗?我猜这两个中的一个失败了。Lazy-of-T中的监视器用法相当微妙。但是根据@bfree-Lazy自动执行…?默认的ctor指定
ExecutionAndPublication
。Bfree是正确的,您可以只使用默认的ctor。当它使用Monitor时,它并不是以我称之为“简单”的方式这样做的。