2010-06-27 18 views
15

Wenn Sie die MSDN-Dokumentation lesen, wissen Sie immer, ob eine Klasse Thread-sicher ist oder nicht. Meine Frage ist, wie Sie eine Klasse threadsicher gestalten? Ich spreche nicht über das Anrufen der Klasse mit Sperren Ich meine, ich arbeite für Microsoft create XXX class \ object und ich möchte sagen, es ist "Thread Safe", was müsste ich tun?Entwerfen einer Thread-Safe-Klasse

+1

Siehe z.B. http://stackoverflow.com/questions/564319/achiting-thread-safety. –

+0

Ich versuche nicht, die Threadsicherheit zu überprüfen. Ich frage, was Sie berücksichtigen müssen, um es zu entwerfen ... – Shane

Antwort

8

Die einfachste und sicherste Art, einen Klassenfaden sicher zu machen, ist immutable. Das Schöne daran ist, dass Sie sich nie wieder mit dem Sperren beschäftigen müssen.

Rezept: Stellen Sie alle Instanzvariablen readonly in C# (final in Java).

  • Ein unveränderliches Objekt, das im Konstruktor erstellt und initialisiert wurde, kann nicht geändert werden.
  • Ein unveränderliches Objekt ist threadsicher. Zeitraum.
  • Dies ist nicht das Gleiche wie eine Klasse mit nur Konstanten.
  • Für änderbare Teile Ihres Systems müssen Sie weiterhin die Sperr-/Synchronisierungseigenschaften berücksichtigen und verarbeiten. Dies ist ein Grund, um unveränderliche Klassen überhaupt zu schreiben.

Siehe auch question.

+1

Ich stimme mit Ihnen aus 2 Gründen nicht überein. 1. Es gibt verschiedene Arten von Unveränderlichkeit, mit denen wir arbeiten. http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx 2. "final" ist Java, Sie meinst du sie Konstanten machen? Wenn ja, stimme ich nicht zu. Alle Felder in den Klassenkonstanten zu machen unterscheidet sich sehr von der Tatsache, dass sie threadsicher sind. – ram

+1

Unbeweglich zu sein ist nutzlos, wenn Sie Threads benötigen, um tatsächlich Daten zu teilen (was ich auf Grund der Frage annehme). – Gabe

+1

Abschließend meine ich _make sicher, es hat einen Wert nach dem Konstruktor, und dieser Wert wird nur einmal zugewiesen_ gelesen. Es gibt viele Beispiele, die meinen Standpunkt beweisen, dh http://blogs.msdn.com/b/lucabol/archive/2007/12/06/creating-an- immutable-value-object-in-c- part -ii-making-the-class-better.aspx http://pebblessteps.com/post/Introduction-to-Immutability-in-C.aspx –

4

Um anzugeben, dass die Klasse threadsicher ist, geben Sie an, dass die internen Datenstrukturen in der Klasse nicht durch den gleichzeitigen Zugriff durch mehrere Threads beschädigt werden. Um diese Behauptung zu machen, müssten Sie das Sperren (Synchronisieren in Java) um kritische Code-Abschnitte innerhalb der Klasse einführen, was möglicherweise zur Beschädigung derselben führen könnte, die von mehreren gleichzeitigen Threads ausgeführt wurden.

+0

Sie müssen die Verriegelung nicht unbedingt einführen. Mit System.Threading.Interlocked. * Können Sie einige schöne Dinge tun. – Spence

+0

Ein anderer, vielleicht einfacherer Weg, diese Behauptung zu machen, besteht darin, alle Instanzvariablen 'readonly' zu markieren, um die Klasse unveränderlich zu machen. –

0

nicht generische ICollection Klassen bieten Eigenschaften für die Fadensicherheit. IsSynchronized und SyncRoot. Leider können Sie IsSynchronized nicht einstellen. Sie können mehr über sie lesen here

In Ihren Klassen können Sie etwas ähnliches zu IsSynchronized und Syncroot, öffentliche Methoden/Eigenschaften allein und innerhalb der Methode Körper überprüfen für sie offen legen. Ihre IsSynchronized wird eine Nur-Lese-Eigenschaft sein, so dass, sobald die Instanz initialisiert wird, werden Sie nicht in der Lage sein, es zu ändern

bool synchronized = true; 
var collection = new MyCustomCollection(synchronized); 
var results = collection.DoSomething(); 

public class MyCustomCollection 
{ 
    public readonly bool IsSynchronized; 
    public MyCustomCollection(bool synchronized) 
    { 
    IsSynchronized = synchronized 
    } 

    public ICollection DoSomething() 
    { 
    //am wondering if there is a better way to do it without using if/else 
    if(IsSynchronized) 
    { 
    lock(SyncRoot) 
    { 
     MyPrivateMethodToDoSomething(); 
    } 
    } 
    else 
    { 
     MyPrivateMethodToDoSomething(); 
    } 

    } 
} 

Sie können mehr lesen über Thread schreiben sichere Sammlungen auf Jared Parson's blog

0

Die Dokumentation nicht schlagen vor, dass Klassen Thread-sicher sind, nur Methoden sind. Um zu bestätigen, dass eine Methode Thread-sicher ist, muss sie gleichzeitig von mehreren Threads aufgerufen werden können, ohne falsche Ergebnisse zu liefern (bei falschen Ergebnissen würde die Methode den falschen Wert zurückgeben oder das Objekt in einen ungültigen Zustand versetzt).

Wenn die Dokumentation sagt

Alle öffentlichen static (Shared in Visual Basic) Member dieses Typs sind thread sicher.

Es bedeutet wahrscheinlich, dass die statischen Member der Klasse den freigegebenen Zustand nicht mutieren.

Wenn die Dokumentation sagt

Jede Instanz Mitglieder sind nicht sicher fädeln garantiert.

bedeutet es wahrscheinlich, dass Methoden minimale interne Verriegelung haben.

Wenn die Dokumentation sagt

Alle öffentlichen und geschützten Mitglieder dieser Klasse sind Thread-sicher und verwendet gleichzeitig von mehreren Threads sein kann.

bedeutet es wahrscheinlich, dass alle Methoden, die Sie aufrufen können, die entsprechende Sperre in ihnen verwenden. Es ist auch möglich, dass die Methoden keinen gemeinsam genutzten Status mutieren oder dass es sich um eine blockierungsfreie Datenstruktur handelt, die eine gleichzeitige Verwendung ohne Sperren zulässt.

0

Bei Thread-sicheren Klassen handelt es sich ausschließlich um den Schutz der Daten (Instanzvariablen) in Ihrer Klasse. Die gebräuchlichste Methode ist das Schlüsselwort lock. Der häufigste Fehler Neuling ist die gesamte Klasse statt einer feingranularen Sperre verwenden sperren:

lock (this) 
{ 
    //do somethnig 
} 

Das Problem mit diesem ist, dass es eine große Leistungseinbußen geben kann, wenn die Klasse tut etwas Wichtiges. Die allgemeine Regel ist, so wenig wie möglich so kurze Zeit wie möglich zu sperren.

können Sie mehr hier lesen: lock keyword in C#

Wenn Sie multithreadnig mehr haben strarted zu verstehen, tief Sie auch einen Blick auf ReaderWriterLoch und Semaphore nehmen. Aber ich schlage vor, dass Sie nur mit dem Schlüsselwort lock beginnen.

5

Zusätzlich zu den anderen ausgezeichneten Antworten hier, auch einen anderen Blickwinkel.

Es ist nicht genug, dass die interne Datenstruktur der Klasse zu 100% Thread-sicher ist, wenn die öffentliche API mehrstufige Operationen hat, die nicht threadsicher verwendet werden können.

Betrachten Sie eine Listenklasse, die so erstellt wurde, dass unabhängig davon, wie viele Threads ausgeführt werden, unabhängig davon, wie viele Arten von Operationen ausgeführt werden, die interne Datenstruktur der Liste immer konsistent und OK ist.

Betrachten Sie diesen Code:

if (list.Count > 0) 
{ 
    var item = list[0]; 
} 

Das Problem hierbei ist, dass der Inhalt der Liste zwischen dem Lesen der Count Eigenschaft und das Lesen des ersten Elements durch die [0] Indexer, könnte ein anderer Thread ausgeräumt .

Diese Art der Threadsicherheit wird normalerweise vergessen, wenn die öffentliche API erstellt wird. Hier besteht die einzige Lösung darin, dass der aufrufende Code bei jedem Zugriffstyp manuell etwas blockiert, um den Absturz des Codes zu verhindern.

Eine Möglichkeit, dies zu lösen, wäre für den Listentyp Autor sein, um typische Nutzungsszenarien zu berücksichtigen und die entsprechenden Methoden der Art hinzufügen:

public bool TryGetFirstElement(out T element) 

dann würden Sie haben:

T element; 
if (list.TryGetFirstElement(out element)) 
{ 
    .... 

vermutlich TryGetFirstElement arbeitet threadsicher und würde niemals true zur gleichen Zeit zurückgeben, wie es den ersten Elementwert nicht lesen kann.

+1

Es ist erwähnenswert, dass es in vielen Fällen möglich ist, dass eine Klasse verschiedene Arten von Thread-Sicherheit spezifiziert.Zum Beispiel wäre es viel billiger für eine 'IDictionary ' Implementierung zu spezifizieren, dass jede Instanz, auf der 'Delete' nie aufgerufen wurde, mit einer beliebigen Anzahl von Lesern und Schreibern threadsicher ist, vorausgesetzt, dass nicht zwei Writer auf die Derselbe Schlüssel wird gleichzeitig eingegeben, und kein Leser fragt nach einem Schlüssel, dessen Wert geändert wird (der aber vor einer solchen Änderung existiert), es sei denn, "TValue" ist ein Referenztyp, um die volle Threadsicherheit zu versprechen. – supercat