2012-05-07 16 views
31

Dokumentacja ConcurrentDictionary nie wyraźny stan, więc myślę, że nie możemy oczekiwać, że delegaci valueFactory i updateValueFactory mieć ich wykonanie zsynchronizowane (z GetOrAdd() i AddOrUpdate() operacje odpowiednio).Pułapka ConcurrentDictionary - Czy fabryki delegatów z GetOrAdd i AddOrUpdate są zsynchronizowane?

Uważam więc, że nie możemy zaimplementować wykorzystania zasobów wewnątrz nich, które wymagają równoczesnej kontroli bez ręcznego wdrażania naszego własnego kontrolera współbieżnego, może po prostu używając [MethodImpl(MethodImplOptions.Synchronized)] nad delegatami.

Mam rację? Albo fakt, że ConcurrentDictionary jest bezpieczny dla wątków, możemy oczekiwać, że wywołania do tych delegatów są automatycznie synchronizowane (również wątkowo)?

Odpowiedz

33

Tak, masz rację, delegaci użytkowników nie są zsynchronizowani przez ConcurrentDictionary. Jeśli potrzebujesz tych zsynchronizowanych, to twoja odpowiedzialność.

Sam MSDN mówi:

Ponadto, chociaż wszystkie metody ConcurrentDictionary są wątku bezpieczny, nie wszystkie metody są niepodzielne, a konkretnie GetOrAdd i AddOrUpdate. Użytkownik przekazany do tych metod to wywoływany poza wewnętrzną blokadą słownika. (Ma to na celu zapobiec nieznany kod blokuje wszystkie wątki.)

See "How to: Add and Remove Items from a ConcurrentDictionary

To dlatego, że ConcurrentDictionary nie ma pojęcia co delegat podać zrobi lub jego wydajność, więc jeśli to próbę blokady wokół nich może to naprawdę negatywnie wpłynąć na wydajność i zrujnować wartość ConcurrentDictionary.

W związku z tym użytkownik jest odpowiedzialny za zsynchronizowanie swojego przedstawiciela, jeśli jest to konieczne. Powyższy link MSDN rzeczywiście ma dobry przykład gwarancji, które robi i nie robi.

+1

Tak więc pakuję wywołanie metody GetOrAdd w blokadę, ale to powoduje, że cel ConcurrentDictionary jest bezużyteczny. Czy istnieje najlepszy sposób? – John

+0

Jestem nieco zdezorientowany przez to, czy w zasadzie mówimy, że jeśli delegat zostanie przekazany jako klucz, to jego wykonanie nie zostanie zsynchronizowane przy ocenie wartości *? Lub jeśli mamy słownik z typem "delegate" jako wartością ... że kiedy próbujemy wykonać delegata (to znaczy 'słownik [klucz] (argument);'), że wykonanie nie zostanie zsynchronizowane? Czy też całkowicie pomijam ten punkt? Dzięki. – Snoopy

+0

@Snoopy: Delegat oceniający wartość do dodania nie jest zsynchronizowany. Oznacza to, że jeśli twój delegat zrobi coś, co nie jest bezpieczne dla wątków * i * nie spróbujesz sam zsynchronizować tej operacji, wtedy zdarzą się złe rzeczy. Ale rzeczą, której delegat działający jako fabryka wartości nie będzie zazwyczaj robić rzeczy, które z natury nie są bezpieczne dla wątków. Przez większość czasu delegat prawdopodobnie po prostu robi 'new SomeObject()', który jest z pewnością wątkowo bezpieczny, ponieważ jest operacją bezstanową. –

22

Te osoby nie tylko nie są zsynchronizowane, ale nie można ich nawet zagwarantować tylko raz. Można je wykonać kilka razy na każde połączenie z numerem AddOrUpdate.

Na przykład algorytm dla AddOrUpdate wygląda mniej więcej tak.

TValue value; 
do 
{ 
    if (!TryGetValue(...)) 
    { 
    value = addValueFactory(key); 
    if (!TryAddInternal(...)) 
    { 
     continue; 
    } 
    return value; 
    } 
    value = updateValueFactory(key); 
} 
while (!TryUpdate(...)) 
return value; 

Uwaga dwie rzeczy tutaj.

  • Nie ma wysiłku, aby zsynchronizować wykonanie delegatów.
  • Delegaci mogą zostać straceni więcej niż jeden raz, ponieważ są wywoływani w pętli wewnątrz.

Musisz więc upewnić się, że robisz dwie rzeczy.

  • Podaj swoją własną synchronizację dla delegatów.
  • Upewnij się, że uczestnicy nie mają żadnych skutków ubocznych, które zależą od tego, ile razy są wykonywane.
+4

@ Luciano: Właśnie sprawdziłem i 'GetOrAdd' wydaje się wywoływać' ValueFactory' za jednym razem. Tak więc tylko 'AddOrUpdate' ma potencjał wielokrotnego wywoływania delegatów. To może być błąd ze strony Microsoftu ... nie jestem pewien. Odkryłem to przez długi czas, [odpowiadając na podobne pytanie] (http://stackoverflow.com/a/3831892/158779). –

+0

@BrianGideon: Oczywiście, przepraszam, że nie zauważyłem, że mówisz o AddOrUpdate zamiast GetOrAdd. Dzięki za odpowiedź. – Luciano

+0

Czy to zachowanie zmieniło się w jakikolwiek sposób? – Sebastian

Powiązane problemy