当它的.value属性没有锁定时,Lazy <T>如何提供线程安全的延迟加载?

Sid*_*ney 3 c# multithreading

好的,所以我一直在查看Lazy <T>源代码,因为我想扩展它.我知道理论上它应该是线程安全的,但我不知道它是怎么回事.看它就是.value getter,它在读取值之前没有锁定任何东西.

public T Value
{
    get
    {
        Boxed boxed = null;
        if (m_boxed != null )
        {
            // Do a quick check up front for the fast path.
            boxed = m_boxed as Boxed;
            if (boxed != null)
            {
                return boxed.m_value;
            }
              LazyInternalExceptionHolder exc = m_boxed as LazyInternalExceptionHolder;
            Contract.Assert(m_boxed != null);
            exc.m_edi.Throw();
        }

        // Fall through to the slow path.
#if !FEATURE_CORECLR
        // We call NOCTD to abort attempts by the debugger to funceval this property (e.g. on mouseover)
        //   (the debugger proxy is the correct way to look at state/value of this object)
        Debugger.NotifyOfCrossThreadDependency(); 
#endif
        return LazyInitValue();

    }
}
Run Code Online (Sandbox Code Playgroud)

我的理解是,要保证线程安全,在写入和读取时都必须锁定,因为如果读取被写入中断,它可能会返回不正确的数据甚至出错.这种理解是正确的,还是Lazy <T>发生了一些复杂的事情?

Ser*_*rvy 7

对引用类型的变量的读/写是原子的,因此即使没有锁定,这样的读也不可能返回未写入的值.在那里读取的值只有一次被分配,当Lazy生成它的值时,所以值是null,并且它移动到更复杂的逻辑,或者它不是,并且我们已经有一个值要返回.如果它继续运行,它确实使用锁定机制来确保多个线程不会同时尝试创建值.

  • @Lukazoid:这是双重检查锁定的变体。如果您阅读代码,您会发现 m_boxed 在锁外和锁内一次都被检查是否为空,因此存在双重检查。 (2认同)