C#Singleton线程安全

时间:2014-10-15 17:17:18

标签: c# thread-safety

我阅读了Jon Skeet关于如何实现C#单例的明确post,并遵循以下模式。请注意,我没有空的ctor。我的Ctor可能会做一些工作,比如创建和填充一个字符串数组(或者它可能会创建一些对象并将它们分配给私有变量等):

public class MyClass
    {                
        /// <summary>
        /// Get singleton instance of this class.
        /// </summary>
        public static readonly MyClass Instance = new MyClass();


        /// <summary>
        /// a collection of strings.
        /// </summary>
        private string[] strings;        

        private MyClass()
        {            
            this.strings = new string[]
            {
                "a",
                "b",
                "c",
                "d",
                "e" 
            };
        }

        public void MyMethod()
        {
           // tries to use this.strings.
           // can a null ref exception happen here when running multithreaded code?
        }
}

高于线程安全吗?我问,因为我有类似的代码在asp.net appserver上运行并在日志中获得null ref异常(不确定null ref是否与上述相关 - 我认为不是 - 并且日志中的调用堆栈没有用)。

2 个答案:

答案 0 :(得分:1)

老实说,我不明白为什么它不应该是线程安全的。特别是考虑到Jon的第四个线程安全版本基本相同。

我看到的唯一问题是你没有静态构造函数。 (这可能会导致问题,请参阅this)如果添加静态构造函数(即使它是空的),您将拥有Jon Skeet所谓的线程安全。

public class MyClass
{
    public static readonly MyClass Instance = new MyClass();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static MyClass() { }
}

答案 1 :(得分:1)

根据提到的Jon Skeet文章,添加静态构造函数将导致此实现是线程安全的:

  

类型初始值设定项的懒惰仅在类型未使用名为beforefieldinit的特殊标志标记时由.NET保证。不幸的是,C#编译器(至少在.NET 1.1运行时中提供)标记所有没有静态构造函数的类型(即看起来像构造函数但被标记为静态的块)为beforefieldinit

(见http://csharpindepth.com/articles/general/singleton.aspx#cctor

如你所知,它不是线程安全的。如果您执行此类操作,则会变为线程安全:

public class MyClass
{
    /// <summary>
    /// Get singleton instance of this class
    /// </summary>
    public static readonly MyClass Instance = new MyClass();

    static MyClass()
    {
        //causes the compiler to not mark this as beforefieldinit, giving this thread safety
        //for accessing the singleton.
    }

    //.. the rest of your stuff..
}