2012-06-19 8 views
19

Ich frage mich, ob Linq Erweiterungsmethoden atomar sind? Oder muss ich lock irgendein IEnumerable Objekt über Threads verwendet werden, vor jeder Art von Iteration?Sind IEnumerable Linq-Methoden Thread-sicher?

Hat die Deklaration der Variablen volatile irgendwelche Auswirkungen auf diese?

Zusammenfassend, welche der folgenden ist die beste, Thread-sichere, Operation?

1- ohne Schleusung:

IEnumerable<T> _objs = //... 
var foo = _objs.FirstOrDefault(t => // some condition 

2- inklusive Schloss Aussagen:

IEnumerable<T> _objs = //... 
lock(_objs) 
{ 
    var foo = _objs.FirstOrDefault(t => // some condition 
} 

3- Deklarieren Variable als flüchtiges:

volatile IEnumerable<T> _objs = //... 
var foo = _objs.FirstOrDefault(t => // some condition 
+0

Sie sind nicht threadsicher. Siehe http://stackoverflow.com/questions/9995266/how-to-create-a-thread-safe-generic-list – stuartd

Antwort

20

Die Schnittstelle IEnumerable<T> ist nicht threadsicher. Siehe die Dokumentation unter http://msdn.microsoft.com/en-us/library/s793z9y2.aspx, die besagt:

Ein Enumerator bleibt gültig, solange die Sammlung unverändert bleibt. Wenn Änderungen an der Auflistung vorgenommen werden, z. B. Elemente hinzufügen, ändern oder löschen, wird der Enumerator unwiderruflich ungültig und sein Verhalten ist nicht definiert.

Der Enumerator hat keinen exklusiven Zugriff auf die Sammlung. Daher ist das Aufzählen durch eine Sammlung an sich kein Thread-sicheres Verfahren. Um die Threadsicherheit während der Enumeration zu gewährleisten, können Sie die Auflistung während der gesamten Enumeration sperren. Um der Sammlung den Zugriff durch mehrere Threads zum Lesen und Schreiben zu ermöglichen, müssen Sie eine eigene Synchronisation implementieren.

Linq ändert nichts davon.

Locking kann natürlich verwendet werden, um den Zugriff auf Objekte zu synchronisieren. Sie müssen das Objekt jedoch überall dort sperren, wo Sie darauf zugreifen, nicht nur wenn Sie darüber iterieren.

Die Deklaration der Sammlung als volatil wird keinen positiven Effekt haben. Es führt nur zu einer Speicherbarriere vor einem Lesen und nach einem Schreiben des Verweises auf die Sammlung. Das Lesen oder Schreiben der Sammlung wird nicht synchronisiert.

7

Kurz gesagt, sind sie nicht Thread-sicher wie oben erwähnt.

Das bedeutet jedoch nicht, dass Sie vor "jeder Art von Iteration" sperren müssen.

Sie müssen alle Vorgänge, die die Auflistung ändern (Elemente hinzufügen, ändern oder entfernen) mit anderen Operationen (Hinzufügen, Ändern, Entfernen von Elementen oder Lesen von Elementen) synchronisieren.

Wenn Sie nur gleichzeitig Lesevorgänge für die Sammlung durchführen, ist keine Sperre erforderlich. (So ​​laufen LINQ-Befehle wie Average, Contains, ElementAtOrDefault alle zusammen)

Wenn die Elemente in der Auflistung der Maschinenwortlänge sind, wie Int auf den meisten 32-Bit-Computern, dann ändern Sie den Wert dieses Elements wird bereits atomar durchgeführt.Fügen Sie in diesem Fall keine Elemente aus der Auflistung hinzu oder entfernen Sie sie nicht, ohne sie zu sperren. Das Ändern von Werten ist jedoch in Ordnung, wenn Sie in Ihrem Entwurf nichtdeterministisch vorgehen können.

Schließlich können Sie feinkörniges Sperren für einzelne Elemente oder Abschnitte der Sammlung in Erwägung ziehen, anstatt die gesamte Sammlung zu sperren.

Verwandte Themen