C#static 생성자를 스레드에 안전합니까?
-
08-06-2019 - |
문제
즉,이는 단일 구현을 쓰레드에 안전하:
public class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance
{
get { return instance; }
}
}
해결책
Static 생성자를 보장하는 것만 실행하면 응용 프로그램당 도메인 전에,모든 클래스의 인스턴스를 만들거나 어떤 정적 멤버에 액세스할 수 있습니다. http://msdn.microsoft.com/en-us/library/aa645612.aspx
구현은 다음과 같은 스레드에 안전에 대한 초기의 건축,즉,잠금 또는 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();
}
}
다른 팁
이 모든 답변을 제공 같은 일반적인 답변,거기에 하나의 실행할 수 있습니다.
을 기억하는 모든 잠재적인 파생어의 일반적인 클래스로 컴파일되는 개인 형식입니다.그래서 주의 사용을 구현하는 경우 정적 생성자에 대한 일반적인 형식입니다.
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
를 사용하여 정적 생성자를 실제로 가 면.Static 생성자를 실행됩니다.
C#어 사양 http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx:
Static 생성자를 위한 클래스를 실행합에서 가장 번에 지정된 응용 프로그램 도메인에 있습니다.의 실행에 정적 생성자에 의해 트리거의 첫 번째 다음과 같은 이벤트가 발생하는 응용 프로그램 내에 도메인:
- 클래스의 인스턴스를 만듭니다.
- 모든 정의 멤버 클래스를 참조됩니다.
그래서 신뢰할 수 있는 단일 것이 올바르게 인스턴스화됩니다.
Zooba 한 모든 지점(15 초 내 앞에,너무!) 는 정적 생성자를 보증하지 않습니다 thread-safe 공유 액세스를 단일.는 것이 처리해야 하에서 다른 방식이다.
여기에 Cliffnotes 버전에서 위 MSDN 페이지에서는 c#단일:
를 사용하여 다음과 같은 패턴을 만들어,당신은 잘못 될 수 없:
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton(){}
public static Singleton Instance
{
get
{
return instance;
}
}
}
저희는 단일 기능을 제공,당신은이 두 가지에 대한 무료(에 대해서는 싱글에서는 c++):
- lazy 건설(또는 건설하는 경우 그것은 결코 이라고)
- 동기화
Static 생성자를 보장하는 불만 일단 당 응용 프로그램 도메인의 접근을 확인해야합니다.그러나,그것이 기능적으로 다르에서 더 많은 간결하고,인라인 버전:
private static readonly Singleton instance = new Singleton();
스레드에 안전이 문제가 더 있을 때 느리게 초기화하는 것들입니다.
이 일반적인 언어는 인프라 사양 는 보장은"형식 이니셜라이저를 실행하여 정확하게 위해 한 번에 지정된 형지 않는 한 명시적으로 호출하여 사용자 코드입니다." (섹션 9.5.3.1.) 그렇지 않으면 당신은 어떤 외 IL 에 느슨한 호출하는 단일::.cctor 직접적으로(가)정적 생성자를 것입니다 정확히 실행하기 전에 한 번에 단일 형식을 사용하는 단 하나의 인스턴스의 단일 창조될 것이고 귀하의 인스턴스의 속성은 스레드에 안전합니다.
한 경우에는 단일의 생성자를 인스턴스에 액세스하산(조 간접적으로)다음의 인스턴스 숙박 시설은 null 입니다.최고 당신이 할 수 있는 감지하는 경우 이런 예외를 확인하여 해당 인스턴스가 null 이 아닌지에서 속성 접근.후에 정적 생성자를 완료한 인스턴스를 제공하지 않는 것입니다 null 입니다.
로 Zoomba 의 응답 지 확인 해야 하는 단일 안에 액세스하에서 여러 스레드 또는 구현 잠금 메커니즘을 사용하여 주위의 싱글턴 인스턴스입니다.
Static 생성자 완료 실행 기 모든 쓰레드에 액세스할 수 있다.
private class InitializerTest
{
static private int _x;
static public string Status()
{
return "_x = " + _x;
}
static InitializerTest()
{
System.Diagnostics.Debug.WriteLine("InitializerTest() starting.");
_x = 1;
Thread.Sleep(3000);
_x = 2;
System.Diagnostics.Debug.WriteLine("InitializerTest() finished.");
}
}
private void ClassInitializerInThread()
{
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() starting.");
string status = InitializerTest.Status();
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() status = " + status);
}
private void classInitializerButton_Click(object sender, EventArgs e)
{
new Thread(ClassInitializerInThread).Start();
new Thread(ClassInitializerInThread).Start();
new Thread(ClassInitializerInThread).Start();
}
위의 코드를 생성한 결과다.
10: ClassInitializerInThread() starting.
11: ClassInitializerInThread() starting.
12: ClassInitializerInThread() starting.
InitializerTest() starting.
InitializerTest() finished.
11: ClassInitializerInThread() status = _x = 2
The thread 0x2650 has exited with code 0 (0x0).
10: ClassInitializerInThread() status = _x = 2
The thread 0x1f50 has exited with code 0 (0x0).
12: ClassInitializerInThread() status = _x = 2
The thread 0x73c has exited with code 0 (0x0).
도 static 생성자의 시간을 실행하고,다른 스레드를 멈추고 기다렸습니다.모든 쓰레드의 값을 읽어 _x 세트의 맨 아래에서 정적 생성자입니다.
그냥 현학적,그러나 같은 것은 없으로 정적인 생성자이지만,오히려 정체되 이니셜라이저 유형, 여기에 작은 모의 순환적인 정적 생성자를 종속성을 보여줍니다 이 점이다.
정적 생성자를 보장할 스레드에 안전합니다.또한 토론에서는 싱글에 DeveloperZen:http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code-1-discussion/
지만 다른 답변은 주로 정확한 있는 또 다른 경고 정전기와 생성자입니다.
당 섹션 II.10.5.3.3 인종 및 교착 상태 의 ECMA-335Common Language 인프라
유형을 초기화하지 아니하며 혼자 교착 상태를 만들지 않으면 일부 코드 라는 형식의 이니셜라이저(직접적 또는 간접적으로)명시적으로 를 호출을 차단 작업입니다.
다음 코드에서는 교착 상태
using System.Threading;
class MyClass
{
static void Main() { /* Won’t run... the static constructor deadlocks */ }
static MyClass()
{
Thread thread = new Thread(arg => { });
thread.Start();
thread.Join();
}
}
원래 저자가 이고르,제작,자신의 게시물 기.