C# - Multithread-Liste Operationen
Wenn ich so etwas wie diese (pseudocode):
class A
{
List<SomeClass> list;
private void clearList()
{
list = new List<SomeClass>();
}
private void addElement()
{
list.Add(new SomeClass(...));
}
}
ist es möglich, dass ich mit multithreading Probleme (oder jede Art von unerwartetem Verhalten), wenn beide Funktionen parallel ausgeführt?
Den Anwendungsfall ist eine Liste der Fehler, die behoben werden konnten jederzeit (durch eine einfache Zuweisung eine neue, leere Liste).
EDIT: Meine Annahmen sind
- nur ein thread fügt Elemente
- vergessen-Elemente sind okay (also race-Bedingung zwischen dem clearing und zum hinzufügen eines neuen Elements), solange die übersichtliche Bedienung gelingt ohne Probleme
- .NET 2.0
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es zwei Möglichkeiten für Probleme:
AddElement
undClearList
sind aufgerufen, an der gleichen Zeit, haben Sie eine race-Bedingung: entweder wird das element in die neue Liste, oder in die alte (vergessene) ein.List<T>
ist nicht sicher für multi-threaded-mutation, so dass, wenn zwei verschiedene threads rufenAddElement
zur gleichen Zeit, die Ergebnisse sind nicht garantiertGegeben, dass Sie den Zugriff auf eine gemeinsame Ressource ist, würde ich persönlich die Sperre beim Zugriff auf Sie. Müssen Sie immer noch die Möglichkeit zu prüfen, löschen der Liste unmittelbar vor/nach hinzufügen eines Elements obwohl.
EDIT: Mein Kommentar etwa, dass es okay, wenn Sie nur das hinzufügen von einem thread war schon etwas dubios, aus zwei Gründen:
List<T>
die noch nicht vollständig aufgebaut noch. Ich bin mir nicht sicher, und die .NET 2.0-Speicher-Modell (im Gegensatz zu der in der ECMA-Spezifikation) kann stark genug sein, um das zu vermeiden, aber es ist schwierig zu sagen.list
variable sofort, und noch die alte Liste. In der Tat, ohne alle Synchronisation, es könnte, sehen Sie den alten Wert für immerWenn Sie hinzufügen, "Iteration in der GUI" in den mix wird es wirklich sehr schwierig - da kann man nicht die Liste ändern, während Sie Durchlaufen. Die einfachste Lösung ist wohl, eine Methode, die zurückgibt einen kopieren der Liste, und die UI kann sicher Durchlaufen das:
Clear
auf alle, sondern ich bin eine neue Liste zu erstellen. Wäre es ein problem zu nennenClear
undAdd
zur gleichen Zeit (Sie sagteList
ist nicht thread-safe)?foreach(Element e in instanceOfC.list) { ... }
- wenn ich das zuweisen einer neuenList
während dieser iteration, die GUI wird immer noch funktionieren auf der alten Liste, richtig?Ja - es ist möglich,. In der Tat, wenn diese wirklich aufgerufen wird, in der gleichen Zeit, ist es sehr wahrscheinlich.
Darüber hinaus ist es wahrscheinlich auch zu Problemen führen, wenn zwei getrennte Aufrufe von addElement zur gleichen Zeit auftreten.
Für diese Art von multithreading, die Sie wirklich brauchen, eine Art von sich gegenseitig ausschließenden Sperre um die Liste selbst, so dass nur ein Vorgang auf der zugrunde liegenden Liste kann aufgerufen werden, zu einer Zeit.
Einem feuchten locking-Strategie, um dieses helfen würde. So etwas wie:
Sammlungen .NETTO (bis zu 3,5) sind nicht thread-sicher oder nicht-blockierend (parallele Ausführung). Sie implementieren sollten Ihnen durch die Ableitung von IList und verwenden Sie eine ReaderWriterLockSlim für die Durchführung jeder Aktion. Zum Beispiel, Ihre Add-Methode sollte so Aussehen:
Müssen Sie sich bewusst sein, einige Parallelität tricks hier. Zum Beispiel müssen Sie über eine GetEnumerator liefert eine neue Instanz als IList; nicht die eigentliche Liste. Sonst läufst du in die Probleme; das sollte dann folgendermaßen Aussehen:
und:
Hinweis: Bei der Implementierung einer thread-sicheren-oder parallel-Sammlungen (und in der Tat jede andere Klasse) NICHT daraus, dass DIE KLASSE, ABER die SCHNITTSTELLE! Denn es gibt immer Probleme mit der internen Struktur von Klassen oder Methoden sind nicht virtuell, und Sie haben Sie zu verbergen und so weiter. Wenn Sie dies tun haben, tun Sie es sehr sorgfältig!
Wenn Sie eine Instanz dieser Klasse in mehrere threads, ja. Sie führen zu Problemen. Alle collections in der .Net framework (version 3.5 und tiefer) sind NICHT thread-sicher. Speziell, wenn Sie beginnen, ändern der Sammlung, während ein anderer thread itterating über es.
Sperren verwenden und geben die Kopien der Sammlungen in Multithread-Umgebungen, oder wenn Sie verwenden können .Net 4.0, die neue concurrent-collections.
Ist es richtig nicht eine gute Sache, einfach eine neue Liste, wenn Sie wollen, um es zu deaktivieren.
Nehme ich Sie auch zugewiesen Liste im Konstruktor, so dass Sie nicht in eine null-pointer-exception.
Wenn Sie klar und Elemente Hinzugefügt, Sie können Hinzugefügt werden, um die alte Liste, die ich annehmen, ist in Ordnung? ABER wenn zwei Elemente Hinzugefügt, zur gleichen Zeit, können Sie auf Probleme stoßen.
Schauen .Net 4 neue Kollektionen zu verarbeiten multithreading-Aufgaben 🙂
ZUSATZ:
Blick in den namespace System.Sammlungen.Die gleichzeitige wenn Sie verwenden .Net 4. Dort finden Sie:
System.Collections.Concurrent.ConcurrentBag<T>
und viele andere schöne Sammlungen 🙂Sollten Sie auch beachten, dass lock kann deutlich nach unten ziehen die Leistung, wenn Sie nicht aufpassen.
lock
?Ist es klar, durch die änderungen auf Ihre Frage, dass Sie nicht wirklich über die üblichen Schuldigen hier - gibt es wirklich keine gleichzeitige Aufrufe an die Methoden des gleichen Objekts.
Im wesentlichen werden Sie gefragt, ob es ok ist, zum zuweisen der Referenz auf Ihrer Liste, während es auf den zugegriffen wird, von einem parallelen thread.
Soweit ich verstehe es immer noch Probleme verursachen können. Es hängt alles davon ab, wie Referenz-Zuordnung erfolgt auf der hardware-Ebene. Um genauer zu sein, ob dieser Vorgang atomar ist oder nicht.
Ich denke, dass so schlank wie es ist, gibt es noch eine chance, vor allem in Multiprozessor-Umgebungen, dass der Prozess beschädigt Referenz, da es wurde, nur teilweise aktualisiert, wenn es war, auf Sie zuzugreifen.