Frage

In anderen Worten, ist das Singleton-Implementierung thread-sicher:

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    static Singleton()
    {
        instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return instance; }
    }
}
War es hilfreich?

Lösung

Statische Konstruktoren werden garantiert nur einmal pro Anwendung Bereich, vor alle Instanzen einer Klasse erstellt werden, oder alle statischen Elemente zugegriffen werden. http://msdn.microsoft.com/en-us/library/aa645612.aspx

Die dargestellten Implementierung ist threadsicher für den ersten Bauabschnitt,, dass ist, keine Sperr-oder null-Tests erforderlich für den Bau des Singleton-Objekt.Jedoch, dies bedeutet nicht, dass Sie die Instanz synchronisiert werden.Es gibt eine Vielzahl von Möglichkeiten, wie dies getan werden kann;Ich habe gezeigt, unten.

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();
    }
}

Andere Tipps

Während all diese Antworten geben die gleiche Allgemeine Antwort, gibt es eine Einschränkung.

Denken Sie daran, dass alle möglichen Ableitungen von einer generischen Klasse kompiliert werden, wie die einzelnen Arten.Seien Sie also vorsichtig bei der Durchführung von statischen Konstruktoren für generische Typen.

class MyObject<T>
{
    static MyObject() 
    {
       //this code will get executed for each T.
    }
}

EDIT:

Hier ist die Demo:

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()));        
    }
}

In der Konsole:

Hit System.Object
Hit System.String

Die Verwendung einer statischen Konstruktor tatsächlich ist threadsicher.Der statische Konstruktor wird garantiert nur einmal ausgeführt werden.

Aus der C# - Sprachspezifikation http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx:

Der statische Konstruktor für eine Klasse führt höchstens einmal in einer bestimmten Anwendungsdomäne.Die Ausführung einer statischen Konstruktor ausgelöst wird, durch die erste der folgenden Ereignisse auftreten, die innerhalb einer Anwendung domain:

  • Eine Instanz der Klasse erstellt wird.
  • Jede von der statischen Mitglieder der Klasse verwiesen werden.

Also ja, Sie können Vertrauen, dass Ihre singleton korrekt instanziiert.

Zooba einen ausgezeichneten Punkt (und 15 Sekunden vor mir, auch!) dass der statische Konstruktor wird nicht garantiert thread-sicheren gemeinsamen Zugriff auf das singleton., Dass müssen behandelt werden, in einer anderen Art und Weise.

Hier ist die Cliffnotes-version aus der obigen MSDN-Seite auf c# - singleton:

Verwenden Sie das folgende Muster, immer, Sie können nicht schief gehen:

public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();

   private Singleton(){}

   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}

Jenseits der offensichtlichen singleton-Funktionen, es gibt Sie, diese zwei Dinge für freies (in Bezug auf singleton in c++):

  1. faul Bau (oder keine Konstruktion, wenn es wurde nie aufgerufen)
  2. Synchronisation

Statische Konstruktoren sind garantiert zu Feuer nur einmal pro App-Domäne, so dass Ihr Ansatz sollte in Ordnung sein.Allerdings ist es funktional keinen Unterschied mehr prägnant, inline-version:

private static readonly Singleton instance = new Singleton();

Thread-Sicherheit ist immer ein Problem, wenn Sie sich faul initialisieren Dinge.

Die Common Language Infrastructure-Spezifikation garantiert, dass "ein Typ Initialisierer wird genau einmal für jede gegebene Art, sofern nicht explizit aufgerufen-user-code." (Abschnitt 9.5.3.1.) So, wenn Sie haben einige verrückte IL auf dem losen aufrufen-Singleton::.cctor direkt (unwahrscheinlich) Ihre statische Konstruktor wird genau einmal ausgeführt, bevor der Singleton-Typ verwendet wird, wird nur eine Instanz der Singleton erstellt werden, und die Instanz-Eigenschaft ist thread-sicher.

Beachten Sie, dass, wenn Singleton-Konstruktor ruft die Instanz-Eigenschaft (auch indirekt) und dann die Instanz-Eigenschaft den Wert "null".Das beste, was Sie tun können, ist zu erkennen, wenn dies geschieht, und eine Ausnahme auslösen, indem Sie die Instanz nicht null ist, in der Eigenschaft verwendet wird.Nach Ihrer statischen Konstruktor abgeschlossen ist die Instanz, wird die Eigenschaft nicht null ist.

Als Zoomba Antwort Punkte aus, die Sie benötigen, um Singleton sicheren Zugriff von mehreren threads, oder implementieren Sie einen locking-Mechanismus, um mithilfe der singleton-Instanz.

Der statische Konstruktor wird finish laufen bevor jeder thread darf den Zugriff auf die Klasse.

    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();
    }

Der obige code erzeugt die Ergebnisse unten.

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).

Auch wenn der statische Konstruktor dauerte eine lange Zeit zu laufen, die anderen threads angehalten und wartete.Alle threads Lesen Sie die Wert von _x set an der Unterseite des statischen Konstruktors.

Nur zu kleinlich, aber es gibt keine solche Sache wie ein statischer Konstruktor, aber eher statisch Typ Initialisierungen hier ist eine kleine demo der zyklischen statische Konstruktor Abhängigkeit, die veranschaulicht diesen Punkt.

Statische Konstruktor wird garantiert threadsicher.Schauen Sie sich auch die Diskussion über Singleton an DeveloperZen:http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code-1-discussion/

Obwohl die anderen Antworten sind meist korrekt, es gibt noch ein weiteres Problem mit der statischen Konstruktoren.

Wie pro Abschnitt II.10.5.3.3 Races und deadlocks der ECMA-335 Gemeinsame Sprache Infrastruktur

Art der Initialisierung ist allein nicht schaffen, einen deadlock, es sei denn, einige code Aufruf aus der typeninitialisierer (direkt oder indirekt) explizit ruft die Blockierung der Operationen.

Der folgende code führt zu einem deadlock

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();
    }
}

Original Autor ist Igor Ostrovsky, finden Sie unter seinen post hier.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top