C#静态构造函数线程安全吗?
换句话说,此Singleton实现线程是否安全:
public class Singleton { private static Singleton instance; private Singleton() { } static Singleton() { instance = new Singleton(); } public static Singleton Instance { get { return instance; } } }
解决方案
回答
通用语言基础结构规范保证"对于任何给定类型,类型初始化器都应精确运行一次,除非由用户代码明确调用。" (第9.5.3.1节)因此,除非我们直接(不太可能)在松散地调用Singleton ::。cctor上有一些怪异的IL,否则静态构造函数在使用Singleton类型之前将只运行一次,否则只会创建一个Singleton实例,并且Instance属性是线程安全的。
请注意,如果Singleton的构造函数访问Instance属性(甚至是间接访问),则Instance属性将为null。最好的办法是通过检查实例在属性访问器中是否为非空来检测何时发生这种情况并引发异常。静态构造函数完成后,Instance属性将为非null。
正如Zoomba的答案所指出的那样,我们将需要使Singleton安全以从多个线程进行访问,或者在使用Singleton实例周围实现锁定机制。
回答
在创建类的任何实例或者访问任何静态成员之前,保证静态构造函数在每个应用程序域仅运行一次。 http://msdn.microsoft.com/en-us/library/aa645612.aspx
所示的实现对于初始构造是线程安全的,也就是说,构造Singleton对象不需要任何锁定或者null测试。但是,这并不意味着实例的任何使用都将被同步。有很多种方法可以做到这一点。我在下面显示了一个。
public class Singleton { private static Singleton instance; // Added a static mutex for synchronising use of instance. private static System.Threading.Mutex mutex; private Singleton() { } static Singleton() { instance = new Singleton(); mutex = new System.Threading.Mutex(); } public static Singleton Acquire() { mutex.WaitOne(); return instance; } // Each call to Acquire() requires a call to Release() public static void Release() { mutex.ReleaseMutex(); } }
回答
使用静态构造函数实际上是线程安全的。保证静态构造函数只能执行一次。
从语言规范http://msdn.microsoft.com/zh-cn/library/aa645612(VS.71).aspx:
The static constructor for a class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain: An instance of the class is created. Any of the static members of the class are referenced.
所以是的,我们可以放心,单例将被正确实例化。
Zooba指出了一个很好的观点(也是在我面前15秒钟!),静态构造函数将不能保证对单例的线程安全共享访问。这将需要以另一种方式来处理。
回答
保证静态构造函数在每个App Domain中仅触发一次,因此方法应该可以。但是,它在功能上与更简洁的嵌入式版本没有什么不同:
private static readonly Singleton instance = new Singleton();
懒惰地初始化事物时,线程安全性更是一个问题。
回答
静态构造函数保证是线程安全的。
另外,在DeveloperZen上查看有关Singleton的讨论:
http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code-1-discussion/
回答
尽管所有这些答案都给出了相同的一般性答案,但有一个警告。
请记住,泛型类的所有潜在派生类都被编译为单个类型。因此,在为泛型类型实现静态构造函数时要格外小心。
class MyObject<T> { static MyObject() { //this code will get executed for each T. } }
编辑:
这是演示:
static void Main(string[] args) { var obj = new Foo<object>(); var obj2 = new Foo<string>(); } public class Foo<T> { static Foo() { System.Diagnostics.Debug.WriteLine(String.Format("Hit {0}", typeof(T).ToString())); } }
在控制台中:
Hit System.Object Hit System.String
回答
只是出于学问的考虑,但是没有静态构造函数,而是静态类型初始化程序,这是一个循环静态构造函数依赖项的小演示,它说明了这一点。