2011-12-22 13 views
9

Dokumentacja ReadOnlyCollection (T) stwierdza, że:ReadOnlyCollection <T> Bezpieczeństwo wątków

A ReadOnlyCollection(Of T) może obsługiwać wiele czytelników jednocześnie, dopóki kolekcja nie jest modyfikowany. Mimo to, wyliczanie przez kolekcję nie jest samoistnie procedurą bezpieczną dla wątków. Aby zagwarantować bezpieczeństwo wątków podczas wyliczania, możesz zablokować kolekcję podczas całego wyliczania. Aby umożliwić dostęp do kolekcji przez wiele wątków do czytania i pisania, musisz zaimplementować własną synchronizację.

Moje pytanie tyczy pogrubiony udział:

  1. dlaczego wylicza poprzez zbiór wewnętrznie nie bezpieczny wątku
  2. jakie są ewentualne konsekwencje i
  3. co powszechnie stosowane obejścia?
+1

Och, chłopcze. bezpieczne listy na .NET zbyt długo. Zobacz niektóre wcześniejsze dyskusje tutaj: http://stackoverflow.com/questions/550616/lock -free-stack-and-queue-in-c-sharp i/lub tutaj: http://stackoverflow.com/questions/66622/threadsafe-foreach-enumeration-of-lists – Radu094

Odpowiedz

7

C# ma całkiem niezły model kolekcji, ale klasa ReadOnlyCollection jest jedną z najbardziej niefortunnie wymyślonych (lub nazwanych) klas w całym modelu. Powinien być bardziej odpowiednio nazwany listą tylko do odczytu, a nie tylko do odczytu.

Teraz, aby uzyskać odpowiedź na twoje pytanie, jest to tylko dekorator IList dostarczony w czasie budowy. Dlatego kod, który skonstruował ReadOnlyCollection, może modyfikować oryginalną listę, ze wszystkimi konsekwencjami, jakie będą to mieć dla dostępu wielowątkowego.

Wyliczenie poprzez kolekcję byłoby bezpieczne dla wątków, gdyby kolekcja była naprawdę tylko do odczytu; ale ponieważ nie jest on tylko do odczytu, nie jest bezpieczny dla wątków. Biorąc pod uwagę ilość reputacji, którą posiadam, jestem pewien, że nie zastanawiasz się, dlaczego wyliczanie poprzez kolekcję nie tylko do odczytu nie jest bezpieczne dla wątków.

Jeśli chodzi o obejście, o które prosiłeś, możesz użyć blokady lub możesz przejść do zasady lock-nothing (lub lock-as-little-as-possible) i utworzyć prawdziwą kopię tylko do odczytu listy.

EDIT

ja ponownie czytając moją odpowiedź na wiele miesięcy później (dzięki asyncwait na komentarz) i zdaję sobie sprawę, że powinienem odpowiedział na wszystkie pytania, PO bez dokonywania założenia oparte na jego reputacji. OP prawdopodobnie otrzymał już odpowiedź, ale zrobię to dla dobra przyszłych czytelników.

Wyliczanie przez kolekcję nie do końca tylko do odczytu nie jest samoistnie wątkowane z tych samych powodów, dla których nawet w scenariuszu z jednym wątkiem nie można zmodyfikować kolekcji podczas jej wyliczania. (ConcurrentModificationException w Javie, InvalidOperationException w języku C#.) W scenariuszu jednowątkowym możesz upewnić się, że twój kod wyliczeniowy nie próbuje zmienić kolekcji w żaden sposób, ale w scenariuszu wielowątkowym jeden wątek może wyliczać kolekcję podczas inny wątek może zmieniać go w tym samym czasie.

+0

Uwaga: Sprawdziłem SSCLI (Rotor) kod źródłowy ReadOnlyCollection przed napisaniem odpowiedzi, aby upewnić się, że rzeczywiście jest to dekorator (opakowanie). –

+0

I sekundę. To tylko opakowanie. Dość bezużyteczne, jeśli twoja kolekcja zostanie zmodyfikowana na zewnątrz przez inną klasę. Imię wprowadza w błąd w świecie nici. – asyncwait

+0

@asyncwait dzięki za komentarz, przypomniało mi, że powinienem dodać poprawkę do mojej odpowiedzi. –

3

Ten MSDN article STAES: „Instancja klasy generycznej ReadOnlyCollection zawsze jest tylko do odczytu.Zbiór, który jest tylko do odczytu jest po prostu zbiorem z obwolutą, który uniemożliwia modyfikację kolekcji "

więc wierzę Iteracja nie jest wątku bezpieczne, ponieważ wewnętrznie używa normalnego non wątek bezpieczny zbiór obiektów.

Powoduje to, że różne wątki mogą uzyskać różne wartości, jeśli w jakiś sposób zmieni się kolekcja.Użyj instrukcji lock, aby uniknąć równoczesnego dostępu do kolekcji z różnych wątków w tym samym czasie:

Powiązane problemy