2013-03-05 9 views
10

Ich arbeite an einer Multithread-C# -Anwendung, die einen WCF-Webdienst verwendet. Die Verbindung zum Webservice wird ein bestimmtes Timeout haben, das wir definieren können und nach dem es geschlossen wird. Ich suche, um die Verbindung zum Webservice mit Singleton-Klasse zu speichern. Ich versuche, die Instanz zu erhalten, wie folgt:Lazy Singleton in einer Multithread-C# -Anwendung

CLazySingleton ins = CLazySingleton.Instance; 
string connection = CLazySingleton.abc; 

Unterhalb der Code für die Singleton-Klasse ist:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace LazySingleton 
{ 
    public class CLazySingleton 
    { 
     private static readonly Lazy<CLazySingleton> _instance 
      = new Lazy<CLazySingleton>(() => new CLazySingleton()); 
     private static readonly object ThreadLock = new object(); 
     public static string abc; 
     //I will use the service connection object in place of 'abc' in the application 
     //assume that 'abc' is storing the connection object  

     private CLazySingleton() 
     { } 

     public static CLazySingleton Instance 
     { 
      get 
      { 
       if (abc == null) 
       { 
        lock (ThreadLock) 
        { 
         //Make the connection 
         abc = "Connection stored in this variable"; 
         Console.WriteLine("Connection Made successfully"); 
         return _instance.Value; 
        }      
       } 
       else 
       { 
        return _instance.Value; 
       } 
      } 
     } 
    } 
} 

Meine Fragen sind: 1. Würde dieser Code in der Lage sein, Pflege mehrerer nehmen Threads versuchen, die Instanz zur gleichen Zeit zu erhalten? Dies ist derzeit meine größte Sorge. 2. Kann ich eine bessere Lösung dafür haben? 3. Muss ich hier 'lock' verwenden oder verwenden Lazy Ansatz kümmert sich um Multithreads versuchen, die Instanz zu bekommen?

Jede Hilfe wäre willkommen.

Danke!

+1

Sie in diesem Artikel von Jon Skeet. Es macht eine gute Arbeit, das Singleton-Muster zu diskutieren. http://www.yoda.arachsys.com/csharp/singleton.html – juharr

+0

Ich habe einige Zweifel an Ihrem Ansatz. Warum müssen Sie einen Singleton für die Verbindung aufrechterhalten? Gibt es ein Problem, wenn jeder Thread seinen eigenen Proxy/Verbindung erhält? Und da es sich um einen Webdienst handelt, sehe ich keine Probleme, wenn Sie viele Verbindungen erstellen. --- Um besser zu verstehen, welche Art von Objekt deine Verbindung ist? – thewpfguy

+0

Sie brauchen die Sperre nicht – Rafa

Antwort

5

Einfache Verwendung ThreadSafetyMode

Lazy<MergeSort> ty = new Lazy<MergeSort>(LazyThreadSafetyMode.ExecutionAndPublication); 
+6

Lazy's Standardkonstruktor verwendet LazyThreadSafetyMode.ExecutionAndPublication, es ist standardmäßig threadsicher. – Phil

+0

Danke, das werde ich sicherlich versuchen. –

8

Laut Microsoft Lazy Initialization Dokumentation unter dem Abschnitt mit dem Titel "Thread-Safe-Initialisierung":

standardmäßig Lazy Objekte sind Thread-sicher.

Vor diesem Hintergrund muss Ihr abc Feld nicht statisch sein. Da Sie ein Lazy<T> verwenden, um Ihr Singleton zu instanziieren, können Sie Ihre Verbindung im CLazySingleton-Konstruktor sicher initialisieren.

+0

Hallo Richard, Danke für die Antwort. Du hast einen guten Punkt gemacht. Selbst ich dachte darüber nach. Aber meine Frage ist, wenn ich die Logik schreibe, um die Verbindung im Konstruktor herzustellen, wie würde ich das Szenario verwalten, in dem die Verbindung nach dem angegebenen Timeout von selbst abgelaufen ist. In diesem Fall wird das Feld abc null und die Singleton-Klasse würde das immer nur als null zurückgeben, da der Konstruktor nicht erneut aufgerufen wird. Ich hoffe, dass ich meinen Standpunkt darlegen konnte. –

+0

Ich denke, Singleton ist nicht das richtige Muster hier, eigentlich müssen Sie Ihre Verbindung auf diese Weise nicht verwalten. Und, bist du sicher, dass du einen Webservice anrufst, denn was ist die Art von Timeout, die du hier erwähnst? – thewpfguy

3

Wäre dieser Code in der Lage, sich um mehrere Threads zu kümmern, die versuchen, die Instanz zur gleichen Zeit zu erhalten?

In Ihrem Szenario kann das Feld "abc" zweimal initialisiert werden. Stellen Sie sich vor, die Variable "abc" ist null. Der erste Thread befindet sich vor der Zuweisung der Werte im Block "Sperren". Der zweite Thread wartet vor der Sperre. Der erste Thread initialisiert also den "abc" und der zweite Thread initialisiert ihn neu (Ihre Überprüfung auf Null ist außerhalb der Sperre, das ist der Grund). Aber vielleicht solltest du davor keine Angst haben.

Kann ich eine bessere Lösung dafür haben?

Ja, Sie können. Lassen Sie mich das im letzten Block dieser Antwort beschreiben.

Muss ich hier 'lock' verwenden oder die Verwendung von Lazy Ansatz kümmert sich um Multithreads versuchen, die Instanz zu bekommen?

Die Erstellung der Value-Eigenschaft in der Lazy-Klasse ist threadsicher. In Ihrem Szenario würde ich den Vorteil der Eigenschaft IsValueCreated von Lazy <> class verwenden. Sie werden weiterhin das ThreadLock-Objekt benötigen.Nur noch eine Sache ist, dass, sobald Sie Eigenschaft Value Lazy <> Klasse zuzugreifen, IsValueCreated Eigenschaft true zurück (das ist der Trick ;-))

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace LazySingleton 
{ 
    public class CLazySingleton 
    { 
     private static readonly Lazy<CLazySingleton> _instance 
      = new Lazy<CLazySingleton>(() => new CLazySingleton()); 
     private static readonly object ThreadLock = new object(); 
     public static string abc; 
     //I will use the service connection object in place of 'abc' in the application 
     //assume that 'abc' is storing the connection object  

     private CLazySingleton() 
     { } 

     public static CLazySingleton Instance 
     { 
      get 
      { 
       if (_instance.IsValueCreated) 
       { 
        return _instance.Value; 
       } 
       lock (ThreadLock) 
       { 
        if (abc == null) 
        { 
         abc = "Connection stored in this variable"; 
         Console.WriteLine("Connection Made successfully"); 
        } 
       } 
       return _instance.Value; 
      } 
     } 
    } 
}