c# – 需要一个锁,需要一个非常不可变类型的懒惰初始化?

如果我有一个非常不可变的类型(所有成员都是只读的,如果它们是引用类型成员,那么它们也指的是不可变的对象).

我想在类型上实现一个懒惰的初始化属性,如下所示:

private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
    get
    {
        if(null == m_PropName)
        {
            ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
            m_PropName = temp;
        }
        return m_PropName;
    }
}

从我能说的:

m_PropName = temp;

…是线程安全的我不担心两个线程同时进行初始化,因为它将是罕见的,两个结果将从逻辑角度来看是一样的,如果我没有,我宁愿不使用锁至.

这会工作吗优缺点都有什么?

编辑:
感谢您的答案.我可能会使用锁向前移动.然而,我很惊讶,没有人提出编译器意识到temp变量是不必要的,只是直接分配给m_PropName的可能性.如果是这样,那么读取线程可能会读取一个尚未完成构造的对象.编译器是否防止这种情况?

(答案似乎表明运行时不会允许这种情况发生.)

编辑:
所以我决定用this article by Joe Duffy的启发式联锁CompareExchange方法.

基本上:

private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
    get
    {
        if(null == m_PropName)
        {
            ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
            System.Threading.Interlocked(ref m_PropName,temp,null);
        }
        return m_PropName;
    }
}

这应该是确保在此对象实例上调用方法的所有线程将获得对同一对象的引用,因此==运算符将工作.有可能浪费工作​​,这是很好的 – 它只是使这是一个乐观的算法.

如下面的一些评论中所指出的,这取决于.NET 2.0内存模型的工作原理.否则,m_PropName应声明为volatile.

解决方法

这将工作.写入C#中的引用保证是原子的,如 spec的5.5节所述.
这仍然可能不是一个好办法,因为您的代码将更加混乱调试和阅读,以换取对性能一个小的影响.

Jon Skeet在C#中执行singeltons有一个很好的page.

关于这样的小型优化的一般建议是不要这样做,除非分析器告诉你这个代码一个热点.此外,您应该谨慎编写大多数程序员无法完全理解的代码,而无需检查规范.

编辑:正如注释中所指出的,即使你说你不介意如果你的对象的2个版本被创建,那么这种情况是非常直观的,这种方法不应该被使用.

相关文章

原文地址:http://msdn.microsoft.com/en-us/magazine/cc163...
前言 随着近些年微服务的流行,有越来越多的开发者和团队所采...
最近因为比较忙,好久没有写博客了,这篇主要给大家分享一下...
在多核CPU在今天和不久的将来,计算机将拥有更多的内核,Mic...
c语言输入成绩怎么判断等级
字符型数据在内存中的存储形式是什么