2012-01-24 12 views
6

I zadeklarowały słownika dicionary:Wracając do słownika w C# w środowisku wielowątkowym

Dictionary<String, Dictionary<String, String>> values; 

Mam getter zdobycia słownika w określonym indeksie:

public Dictionary<String,String> get(String idx) 
{ 
    lock (_lock) 
    { 
     return values[moduleName]; 
    } 
} 

As widać, że pracuję w środowisku wielowątkowym. Moje pytanie brzmi, czy muszę powrócić kopię mojego słownika, aby być bezpieczne jak ten wątek:

public Dictionary<String,String> get(String idx) 
{ 
    lock (_lock) 
    { 
     return new Dictionary<string, string>(values[moduleName]); 
    } 
} 

Jeśli nie będzie klasy, która wywołuje getter otrzymać kopię (więc jeśli usunąć ten słownik z mojego Dictionary<String, Dictionary<String, String>> będzie nadal działał)?

Cheers,

Thierry.

+2

Prawdopodobnie nie powinieneś w ogóle powracać do słownika, ale jeśli tak, to tak, musisz zrobić kopię, gdy znajdujesz się wewnątrz monitora. Czy możesz opisać, jaki powinien być cel tego konstruktu? – Groo

+0

Lub użyj [słownika bezpiecznego dla wątków] (http://msdn.microsoft.com/en-us/library/dd287191.aspx) –

+0

Dziękuję za odpowiedź. –

Odpowiedz

4

Jeśli naprawdę potrzebujesz zwrócić sam słownik, będziesz musiał albo mieć reguły dotyczące tego, w jaki sposób wątki się na nim blokują (kruche, a co jeśli jest przypadek, który nie działa?), Użyj go w czytaniu. Jedyny sposób (słownik jest bezpieczny dla wątków tylko do odczytu, ale zauważ, że zakłada to, że kod prywatny dla klasy również nie jest do niego zapisany), użyj słownika bezpiecznego dla wątków (ConcurrentDictionary używa blokowania pasków, mój ThreadSafeDictionary stosuje podejścia typu "lock-free" i istnieją różne scenariusze, w których jeden bije drugi) lub wykonaj kopię zgodnie z sugestią.

Alternatywnie, jeśli ujawniasz metodę pobierania lub ustawiania ostatecznego ciągu znalezionego przez dwa klawisze, aby wyliczyć klucze drugiego poziomu znalezione przez klucz i tak dalej, nie tylko możesz kontrolować blokowanie wykonane w jednym miejscu, ale ma inne zalety w czystości interfejsu i uwolnieniu implementacji z interfejsu (np. można przejść od blokady do użycia słownika bezpiecznego dla wątków lub odwrotnie, bez wpływu na kod wywołujący).

2

Jeśli nie zwrócisz kopii, dzwoniący będzie mógł zmienić słownik, ale nie jest to problem z bezpieczeństwem wątków.

Istnieje również problem z bezpieczeństwem wątków, ponieważ nie ma żadnych blokad synchronizujących zapisów i odczytów. Na przykład wątek twojego pisarza może dodawać/usuwać wartość, gdy wątek czytnika działa na tym samym egzemplarzu.

Tak, musisz zwrócić kopię.

+0

Możesz po prostu udokumentować, że ludzie używający słownika muszą go gdzieś zablokować. – CodingBarfield

+0

Dziękuję za odpowiedź, w moim przypadku zarówno wywołujący, jak i zawierająca klasa mogą uzyskać dostęp do wartości zwróconego słownika, więc będę musiał wybrać kopię lub współbieżny słownik. –

+0

@CodingBarfield Yup, ale powinieneś ujawnić obiekt synclock, którego używasz do zapełniania słownika, aby wszyscy blokowali ten sam obiekt. Blokowanie samego słownika nie jest zalecane, ale jest to inny temat. – Guillaume

6

Dictionary<> nie jest bezpieczny dla wątków, ale jest ConncurrentDictionary<>.

Klasa wywołująca getter otrzymuje referencję, co oznacza, że ​​nadal będzie istnieć, jeśli usuniesz ją z values -Dictionary, ponieważ GC nie czyści jej tak długo, jak długo masz odniesienie, po prostu nie możesz zabierz go już z geterem.

basicaly oznacza, że ​​masz dwie możliwości podczas korzystania Dictionary<>:

  • zwrot kopia: zły pomysł, bo jeśli zmienić config masz dwie różne konfiguracje w aplikacji „żywy”
  • zablokować wystąpienie: ta stałaby się bezpieczny wątku, ale następnie użyć ConcurrentDictionary<> jak to robi dokładnie to za Ciebie
+0

I pamiętajcie. Przedmioty pobrane z ConcurrentDictionary nie są automatycznie zapisywane w wątkach! – CodingBarfield

+0

Dziękuję za odpowiedź, pomogło mi to lepiej zrozumieć. –

Powiązane problemy