微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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个版本被创建,那么这种情况是非常直观的,这种方法不应该被使用.

原文地址:https://www.jb51.cc/csharp/97456.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐