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.
Zusammenfassend habe ich verstanden, dass die besten Praktiken für die Synchronisierung / Sperrung wie folgt sein sollten:
SyncRoot
bereitstellen (siehe auch dieser Kommentar ). Ist das über dem richtigen Gebrauch dieses Musters geschrieben?
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:
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.
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.
Tags und Links .net c# multithreading thread-safety