Mit anderen Worten, ist dieser Singleton-Implementierungsthread sicher:
public class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance
{
get { return instance; }
}
}
c#
multithreading
singleton
Urini
quelle
quelle
Instance
gleichzeitig erhalten. Einer der Threads wird angewiesen, zuerst den Typinitialisierer (auch als statischer Konstruktor bezeichnet) auszuführen. In der Zwischenzeit werden alle anderen Threads, die dieInstance
Eigenschaft lesen möchten, gesperrt, bis der Typinitialisierer abgeschlossen ist. Erst nach Abschluss des Feldinitialisierers können Threads denInstance
Wert abrufen. So kann niemand dasInstance
Sein sehennull
.X
enden als-1
auch ohne Einfädeln . Es ist kein Thread-Sicherheitsproblem. Stattdessen wird der Initialisiererx = -1
zuerst ausgeführt (er befindet sich in einer früheren Zeile im Code, einer niedrigeren Zeilennummer). Dann wird der Initialisierer ausgeführtX = GetX()
, wodurch GroßbuchstabenX
gleich werden-1
. Und dann wird der "explizite" statische Konstruktor, der Typinitialisiererstatic C() { ... }
, ausgeführt, der nur Kleinbuchstaben ändertx
. Nach all dem kann dieMain
Methode (oderOther
Methode) fortfahren und Großbuchstaben lesenX
. Sein Wert wird-1
auch mit nur einem Thread sein.Antworten:
Statische Konstruktoren werden garantiert nur einmal pro Anwendungsdomäne ausgeführt, bevor Instanzen einer Klasse erstellt oder auf statische Mitglieder zugegriffen wird. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
Die gezeigte Implementierung ist für die anfängliche Konstruktion threadsicher, dh für die Konstruktion des Singleton-Objekts sind keine Sperren oder Nulltests erforderlich. Dies bedeutet jedoch nicht, dass eine Verwendung der Instanz synchronisiert wird. Es gibt verschiedene Möglichkeiten, dies zu tun. Ich habe unten einen gezeigt.
quelle
Lazy<T>
: Jeder, der den Code verwendet, den ich ursprünglich gepostet habe, macht es falsch (und ehrlich gesagt war es anfangs nicht so gut - vor 5 Jahren war ich in diesem Bereich nicht so gut wie aktuell -me ist :)).Während alle diese Antworten die gleiche allgemeine Antwort geben, gibt es eine Einschränkung.
Denken Sie daran, dass alle möglichen Ableitungen einer generischen Klasse als einzelne Typen kompiliert werden. Seien Sie daher vorsichtig, wenn Sie statische Konstruktoren für generische Typen implementieren.
BEARBEITEN:
Hier ist die Demonstration:
In der Konsole:
quelle
Mit eigentlich ein statischer Konstruktor ist THREAD. Der statische Konstruktor wird garantiert nur einmal ausgeführt.
Aus der C # -Sprachenspezifikation :
Ja, Sie können darauf vertrauen, dass Ihr Singleton korrekt instanziiert wird.
Zooba machte einen hervorragenden Punkt (und auch 15 Sekunden vor mir!), Dass der statische Konstruktor keinen thread-sicheren gemeinsamen Zugriff auf den Singleton garantiert. Das muss auf andere Weise gehandhabt werden.
quelle
Hier ist die Cliffnotes-Version von der obigen MSDN-Seite auf c # singleton:
Verwenden Sie immer das folgende Muster, Sie können nichts falsch machen:
Abgesehen von den offensichtlichen Singleton-Funktionen erhalten Sie diese beiden Dinge kostenlos (in Bezug auf Singleton in C ++):
quelle
Statische Konstruktoren werden garantiert nur einmal pro App-Domäne ausgelöst, daher sollte Ihr Ansatz in Ordnung sein. Es unterscheidet sich jedoch funktional nicht von der prägnanteren Inline-Version:
Die Thread-Sicherheit ist eher ein Problem, wenn Sie Dinge träge initialisieren.
quelle
Der statische Konstruktor wird beendet , bevor ein Thread auf die Klasse zugreifen darf.
Der obige Code ergab die folgenden Ergebnisse.
Obwohl die Ausführung des statischen Konstruktors lange gedauert hat, wurden die anderen Threads angehalten und gewartet. Alle Threads lesen den Wert von _x, der am unteren Rand des statischen Konstruktors festgelegt ist.
quelle
Die Common Language Infrastructure-Spezifikation garantiert, dass "ein Typinitialisierer für einen bestimmten Typ genau einmal ausgeführt wird, sofern er nicht ausdrücklich vom Benutzercode aufgerufen wird". (Abschnitt 9.5.3.1.) Wenn Sie also nicht direkt (unwahrscheinlich) eine verrückte IL auf dem losen aufrufenden Singleton ::. Cctor haben, wird Ihr statischer Konstruktor genau einmal ausgeführt, bevor der Singleton-Typ verwendet wird. Es wird nur eine Instanz von Singleton erstellt. und Ihre Instance-Eigenschaft ist threadsicher.
Beachten Sie, dass die Instance-Eigenschaft null ist, wenn der Singleton-Konstruktor (auch indirekt) auf die Instance-Eigenschaft zugreift. Das Beste, was Sie tun können, ist zu erkennen, wann dies geschieht, und eine Ausnahme auszulösen, indem Sie überprüfen, ob die Instanz im Eigenschaften-Accessor nicht null ist. Nach Abschluss Ihres statischen Konstruktors ist die Instance-Eigenschaft nicht null.
Wie die Antwort von Zoomba zeigt, müssen Sie Singleton für den Zugriff von mehreren Threads sicher machen oder einen Sperrmechanismus für die Verwendung der Singleton-Instanz implementieren.
quelle
Nur um pedantisch zu sein, aber es gibt keinen statischen Konstruktor, sondern statische Typinitialisierer. Hier ist eine kleine Demo der Abhängigkeit von zyklischen statischen Konstruktoren, die diesen Punkt veranschaulicht.
quelle
Der statische Konstruktor ist garantiert threadsicher. Schauen Sie sich auch die Diskussion über Singleton unter DeveloperZen an: http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code-1-discussion/
quelle
Obwohl andere Antworten größtenteils richtig sind, gibt es noch eine weitere Einschränkung bei statischen Konstruktoren.
Gemäß Abschnitt II.10.5.3.3 Rennen und Deadlocks der ECMA-335 Common Language Infrastructure
Der folgende Code führt zu einem Deadlock
Der ursprüngliche Autor ist Igor Ostrovsky, siehe seinen Beitrag hier .
quelle