2012-07-26 7 views
10

ich eine Singletonklasse haben ähnlich wie dieseC# Singleton Faden sicher

public class Singleton 
{ 
    private static Singleton m_instance; 
    private Timer m_timer; 
    private static List<CustomObject> m_cacheObjects; 

    private Singleton() 
    {  
     m_cacheObjects = new List<CustomObject>(); 
     m_timer= new Timer(MyTimerCallBack, 
          null, 
          TimeSpan.FromSeconds(60), 
          TimeSpan.FromSeconds(60));   
    } 

    public static Singleton Instance 
    { 
     get 
     { 
      if (m_instance == null) 
      { 
       m_instance = new Singleton(); 
      } 
      return m_instance; 
     } 
    } 

    private void MyTimerCallBack(object state) 
    { 
     //******** Update the list by interval here ****************** 

     m_cacheObjects = UpdateTheList(); 
    } 

    public void CallMe() 
    { 
     foreach (CustomObject obj in m_cacheObjects) 
     { 
      // do something here based on obj 

      // The question is, does the m_cacheObjects is thread safe?? 
      // what happen if the m_cacheObjects is changed 
      // during the loop interation? 
     } 
    } 
} 

CallMe Methode wird durch Web-Service aufgerufen werden 1) Ist die m_cacheObjects Thread sicher? Was passiert, wenn die m_cacheObjects während der Loop-Integration (in der CallMe()) (wegen des Timers) geändert wird?

2) Wird ein neuer Thread erstellt, wenn der Webservice CallMeWebService() aufgerufen wird?

+1

1) a) Nein, 1) b) Sie können nicht sicher sein, 2) Ja – Jodrell

+0

Ich werde die folgenden Antworten folgen, um die statische Initialisierung threadsicher zu machen. – user1553857

+1

Jetzt interessiere ich mich mehr für die statische Liste m_cacheObjects. Ich pausiere implizit (Debug-Modus) in der foreach-Schleife und warte darauf, dass der Timer tickt und die m_cacheObjects-Liste ändert, vermutlich schlägt die foreach-Schleife aufgrund der Änderung der Liste fehl, aber sie läuft ohne Ausnahme weiter. Ist das normal? – user1553857

Antwort

4

Dies ist eine ziemlich gute Ressource, wie die Singletonmuster in einem Thread sichere Art und Weise zu implementieren: http://msdn.microsoft.com/en-us/library/ff650316.aspx

public sealed class Singleton 
{ 
    private static volatile Singleton instance; 
    private static object syncRoot = new Object(); 

    private Singleton() {} 

    public static Singleton Instance 
    { 
     get 
     { 
    if (instance == null) 
    { 
     lock (syncRoot) 
     { 
      if (instance == null) 
      instance = new Singleton(); 
     } 
    } 

    return instance; 
     } 
    } 
} 

Dieses einfach sicher macht, dass es nie als eine Instanz mehr sein. Sie müssen auch die Sperrung für Ihre benutzerdefinierte Methode anwenden.

public void CallMe() 
{ 
    lock (syncRoot) 
    { 
     foreach (CustomObject obj in m_cacheObjects) 
     { 
      // do something here based on obj 
     } 
    } 
} 
+4

@Downvoter Ich habe nichts gegen einen Downvote, wenn ich es verdiene, aber würdest du bitte einen Kommentar dazu schreiben? Wie es einfach scheint, wie einer der anderen Beantworter mich drängen wollte auf die Liste der Antworten, egal was ich sagte – Mithon

8

1: Nein, eine statische Liste ist nicht automatisch Thread-sicher; Sie müssen m_cacheObjects manuell schützen

2: Das ist ein Implementierungsdetail; Auf den ersten Blick sieht es aus wie es sich als Synchronisierungsmethode macht, aber wie tut es, dass ganz bei ihm

Eigentlich Ihre statische Initialisierung entweder nicht Thread-sicher ist; Ich könnte ein Szenario brute-force, wo zwei verschiedene Singleton Instanzen verwendet wurden. Es würde Wiederholung brauchen, um es zu produzieren, aber es würde passieren.

Ehrlich gesagt, wenn Sie einen wirklich guten Grund haben, nicht zu, die einfachste, aber am sichersten Singletonmuster ist einfach:

private static readonly Singleton m_instance = new Singleton(); 
+0

Vielleicht 'Lazy <>'? –

+0

@LB Hinweis Ich erwähnte "einfachste". Um ehrlich zu sein, sind die Situationen, die ein lazy initialized Singleton brauchen sehr selten, a: Singletons sollte selten, b: yo Du müsstest wissen, dass 'Singleton' teuer zu erstellen ist, und c: Du müsstest wissen, dass es nützliche Dinge gibt, die * ohne * benötigt werden können. In diesem Fall denke ich, dass es tatsächlich alle 3 Kriterien nicht erfüllt. –

+0

Mit manuell meinen Sie das Schlüsselwort lock oder etwas anderes? –

0

Es ist nicht Thread-sicher ist.

Ich glaube, dass ich eine Sperre sowohl ‚MyTimerCallBack‘ und ‚CallMe‘ verwenden würden Methoden

0

1) Nein, m_cacheObjects ist nicht Thread-sicher.

2) Ja, es wird ein neuer Thread erstellt (nun, es darf kein neuer Thread sein, sondern Thread, der aus dem Thread-Pool genommen wurde).

Sie müssen m_cacheObjects mit lock Anweisung schützen.Auch in der CallMe Methode würde ich empfehlen, eine lokale Kopie von m_cacheObjects zu erstellen:

// create new field syncRoot 
private static readonly object syncRoot = new object(); 

New CallMe Methode:

List<CustomObject> localCopy; 
lock (syncRoot) 
{ 
    localCopy = new List<CustomObject>(m_cacheObjects); 
} 

foreach (var nextObject in localCopy) 
{ 
// Do some work 
} 

und aktualisierte MyTimerCallBack Methode:

lock (syncRoot) 
{ 
    m_cacheObjects = UpdateTheList(); 
} 

Und bitte Implementieren Sie auch thread-safe Singleton (lesen Sie weitere Antworten für Details). Erklären

+0

Ich verstehe die neue CallMe-Methode. aber nicht sicher über das MyTimerCallBack, wenn ich sicher bin, dass die m_cacheObjects vor dem nächsten Timer-Tick aktualisiert werden, muss ich es noch sperren? – user1553857

+0

Eine einzelne 'lock'-Anweisung macht keinen Sinn. Mit 'lock' in' MyTimerCallback' können Sie sicher sein, dass 'CallMe' wartet, bis MyTimerCallback beendet ist. Und umgekehrt - Lock-in 'CallMe' stellt sicher, dass' m_cacheObjects' nicht aktualisiert wird, bis es in eine 'localCopy' kopiert wird. – Alexander

5
//using System.Runtime.CompilerServices; 

private static volatile Singelton _instance; 

public static Singelton Instance 
{ 
    [MethodImpl(MethodImplOptions.Synchronized)] 
    get 
    { 
     if (_instance == null) 
     { 
      _instance = new Singelton(); 
     } 
     return _instance; 
    } 
} 

:

[MethodImpl (MethodImplOptions.Synchronized)] Dadurch wird der Compiler sagen, dass der Zugriff auf "Instanz" wird "synchronisiert", damit das System über die Anrufe kümmern zu diesem Parameter.

Dies ist Thread-Safe.

EDIT: (Auch die "Sperre()" Beispiele sind nicht sicher Coz, kann u den Faden Sicherheit mit deaktivieren "Monitor.Exit (Singleton);"!)