Hinweis: Ich gehe davon aus, dass die Ausnahme beim Ändern der Sammlung während der Iteration bereits behoben ist
Dictionary ist keine thread-sichere Sammlung, d.h. es ist pas sicher zu ändern und zu lesen Sammlung von verschiedenen Threads ohne externe Synchronisation. Hashtable ist (war?) thread-sicher für das Szenario "ein Schreiber, viele Leser", aber Dictionary hat eine andere interne Datenstruktur und erbt diese Garantie nicht.
Das bedeutet, dass Sie Ihr Wörterbuch nicht ändern können, während Sie von einem anderen Thread darauf zugreifen, um es zu lesen oder zu schreiben, sondern nur interne Datenstrukturen zerstören können. Das Sperren des Schlüssels schützt die interne Datenstruktur nicht, denn während Sie genau diesen Schlüssel ändern, könnte jemand einen anderen Schlüssel Ihres Wörterbuchs in einem anderen Thread lesen. Selbst wenn Sie garantieren können, dass alle Ihre Schlüssel die gleichen Objekte sind (wie bei String-Interning), bringt Sie das nicht auf die sichere Seite. Beispiel:
- Sie sperren den Schlüssel und beginnen, das Wörterbuch zu ändern
- Ein anderer Thread versucht, einen Wert für den Schlüssel zu erhalten, der zufällig in denselben Bucket wie der gesperrte fällt. Dies geschieht nicht nur, wenn die Hashcodes zweier Objekte gleich sind, sondern häufiger, wenn der Hashcode%tableSize gleich ist.
- Beide Threads greifen auf denselben Bucket zu (verknüpfte Liste von Schlüsseln mit demselben Hashcode%tableSize-Wert)
Wenn es keinen solchen Schlüssel im Wörterbuch gibt, beginnt der erste Thread mit der Änderung der Liste, und der zweite Thread wird wahrscheinlich einen unvollständigen Zustand lesen.
Wenn ein solcher Schlüssel bereits vorhanden ist, könnte die Datenstruktur durch Implementierungsdetails des Wörterbuchs noch geändert werden, z. B. durch Verschieben der zuletzt verwendeten Schlüssel an den Anfang der Liste, um sie schneller abrufen zu können. Sie können sich nicht auf Implementierungsdetails verlassen.
Es gibt viele solche Fälle, in denen das Wörterbuch beschädigt ist. Sie müssen also ein externes Synchronisationsobjekt haben (oder das Dictionary selbst verwenden, wenn es nicht öffentlich zugänglich ist) und es während der gesamten Operation sperren. Wenn Sie granularere Sperren benötigen und die Operation lange dauern kann, können Sie die zu aktualisierenden Schlüssel kopieren, darüber iterieren, das gesamte Wörterbuch während der Aktualisierung eines einzelnen Schlüssels sperren (vergessen Sie nicht zu überprüfen, ob der Schlüssel noch vorhanden ist) und die Sperre freigeben, damit andere Threads ausgeführt werden können.
0 Stimmen
Keine Antwort, aber Sie wissen, dass Sie, wenn Sie das Paar bereits haben, pair.Value verwenden können, anstatt operator[] erneut im Dictionary aufzurufen?
0 Stimmen
Ich habe es versucht, aber der Wert ist schreibgeschützt, so hat es mir meine IDE gesagt.
0 Stimmen
Sie können die foreach-Elemente nicht ändern
0 Stimmen
Wo genau liegt die Gleichzeitigkeit, die Sie vermeiden wollen? Wenn Sie Ihre Schleife in mehreren Threads ausführen, sperrt der erste Thread die erste Taste, alle anderen blockieren beim Drücken der ersten Taste. Ich verstehe also das Szenario nicht, das Sie lösen wollen. Könnten Sie Ihre Frage in dieser Hinsicht präzisieren?
0 Stimmen
TToni: Sie haben absolut Recht, aber mein Beispiel hier ist vereinfacht - sie werden nicht in einer Schleife aktualisiert - es war nur ein schlechtes Beispiel, das ich gemacht habe - jeder Thread könnte unterschiedliche Werte aktualisieren - oder das Gleiche, was ich gerne vermeiden würde.
0 Stimmen
Nun, das ist der Grund, warum ich gefragt habe, um die Frage zu klären :-) Es gibt eine ganze Reihe von Diskussionen, die sich darauf konzentrieren, warum die Schleife nicht funktioniert, dass Sie jeden Enumerator der Sammlung ungültig machen, wenn Sie ihn aktualisieren und so weiter. Also, ja, schlechtes Beispiel, bitte wählen Sie ein besseres.
0 Stimmen
Ähnliche Frage: stackoverflow.com/questions/168249/