Einige Erläuterungen zum SyncRoot-Muster: Wie kann dieses Muster richtig verwendet werden?

8

Ich habe etwas über das SyncRoot-Muster als allgemeine Regel gelesen, um Deadlocks zu vermeiden. Und eine Frage von vor ein paar Jahren lesen (siehe link ) Ich glaube, ich verstehe, dass einige Anwendungen dieses Musters falsch sind. Insbesondere habe ich mich auf die folgenden Sätze aus diesem Thema konzentriert:

  

Sie werden eine SyncRoot-Eigenschaft für viele Collections in System.Collections bemerken. Im Nachhinein glaube ich, dass diese Eigenschaft eine war   Fehler ... Seien Sie versichert, wir werden nicht den gleichen Fehler machen wie wir bauen   die generischen Versionen dieser Sammlungen.

Tatsächlich implementiert zum Beispiel die Klasse List<T> nicht die Eigenschaft SyncRoot , oder genauer gesagt, sie wird explizit implementiert (siehe dies antworte ), also musst du in ICollection umwandeln, um es zu benutzen. Aber dieser Kommentar spricht dafür, ein privates SyncRoot -Feld zu erstellen public ist so schlecht wie lock on this (siehe diese Antwort ), wie auch bestätigt in diesen Kommentar .

Wenn ich also richtig verstehe, sollte ich, wenn ich eine nicht threadsichere Datenstruktur implementiere, nicht in der Lage sein, die SyncRoot -Eigenschaft zur Verfügung zu stellen (eigentlich nicht). Aber ich sollte den Entwickler (der diese Datenstruktur verwendet) mit der Aufgabe assoziieren, ihn mit einem privaten SyncRoot-Objekt wie im folgenden Beispielcode zu verknüpfen.

%Vor%

Zusammenfassend habe ich verstanden, dass die besten Praktiken für die Synchronisierung / Sperrung wie folgt sein sollten:

  1. Alle privaten SyncRoot-Objekte sollten nicht über eine öffentliche Eigenschaft verfügbar gemacht werden. Mit anderen Worten, eine benutzerdefinierte Datenstruktur sollte keine öffentliche Eigenschaft SyncRoot bereitstellen (siehe auch dieser Kommentar ).
  2. Im Allgemeinen ist es nicht obligatorisch, private Objekte zum Sperren zu verwenden (siehe diese Antwort ).
  3. Wenn eine Klasse über mehrere Gruppen von Operationen verfügt, die synchronisiert werden müssen, aber nicht miteinander, sollten mehrere private SyncRoot-Objekte vorhanden sein (siehe Dieser Kommentar ).

Ist das über dem richtigen Gebrauch dieses Musters geschrieben?

    
enzom83 14.09.2012, 12:53
quelle

2 Antworten

4

Ich würde vermeiden, eine SyncRoot Eigenschaft zu dem Typ hinzuzufügen, den ich entwerfe, hier sind die Gründe:

  • Benutzer meines Typs müssen möglicherweise einen anderen Synchronisierungsmechanismus verwenden, zum Beispiel Mutex oder ReaderWriterLock oder ReaderWriterLockSlim usw.

  • Der Typ wird fetter: seine Verantwortung wird verstreuter. Warum sollte ich Unterstützung für das explizite Multithreading-Locking und keine Unterstützung für andere Fluffs hinzufügen? Ich würde den Benutzer zwingen, nur einer Übung zu folgen, die in allen Fällen nicht die beste Lösung ist.

  • Ich müsste die Eigenschaft korrekt implementieren (keine Rückgabe von this oder typeof(MyClass) ), d. h. das ist falsch:

    %Vor%

Ich würde auch vermeiden, SyncRoot -Eigenschaft aus den .NET-Framework-Typen zu verwenden. Wenn ich einen Typ ohne SyncRoot Eigenschaft threadsafe machen muss, verwende ich ein Sperrmuster, und wenn ein Typ diese Eigenschaft hat, werde ich immer noch nicht für SyncRoot sperren. Dadurch wird mein Codestil konsistenter und einfacher zu lesen / zu warten.

    
oleksii 14.09.2012, 13:52
quelle
0

Hier gibt es eine Reihe von Konzepten. Erstens, was Sie richtig implementiert haben, ist eine Thread-sichere Klasse, in der keine Konsumenten der Klasse ihre eigene Synchronisation durchführen müssen. Daher müssen Sie das syncRoot-Objekt nicht unbedingt verfügbar machen. In den alten Collection-Klassen wurde die SyncRoot-Eigenschaft verfügbar gemacht, da die Klassen nicht threadsicher waren.

Beim Sperren eines beliebigen Objekts und Sperren Ihrer inneren Sammlung gibt es absolut keinen Unterschied in Bezug auf die Korrektheit oder Leistung des Programms. Solange sich der Verweis auf beides nicht ändert, funktionieren sie genauso gut wie Parameter für Monitor.Enter / Exit. Wird sich deine innere Sammlung verändern? Wenn nein, markieren Sie es auch als Nur-Lesen.

Drittens gibt es den Kommentar bezüglich der Verwendung von verschiedenen Schlössern basierend auf verschiedenen Operationen. Das klassische Beispiel hierfür ist der ReaderWriterLock. Sie sollten die Notwendigkeit analysieren, verschiedene Sperren auf der Grundlage der verschiedenen Funktionen zu verwenden, die von Ihrer Klasse bereitgestellt werden.

    
Slugart 14.09.2012 13:33
quelle