Kiedy ConcurrentDictionary TryRemove zwróci wartość false

79

Czy zwróci fałsz tylko wtedy, gdy słownik nie zawiera wartości dla danego klucza, czy też zwróci fałsz z powodu warunków wyścigu wątków, tak jak inny wątek coś dodaje / aktualizuje?

Pytanie w kodzie:

ConcurrentDictionary<int, string> cd = new ConcurrentDictionary<int, string>();

// This might fail if another thread is adding with key value of 1.
cd.TryAdd(1, "one"); 

// Will this ever fail if no other thread ever removes with the key value of 1?
cd.TryRemove(1); 

Edycja: Myślę, że zwróci false tylko wtedy, gdy nie zawiera wartości dla danego klucza, ale chcesz być absolutnie pewien.

Martin Ingvar Kofoed Jensen
źródło

Odpowiedzi:

85

Chociaż Mitch ma rację, że a ConcurrentDictionarynie jest podatny na warunki wyścigu, myślę, że odpowiedź na pytanie, które zadajesz, brzmi: tak, jeśli klucz jest obecny, TryRemovezadziała i powróci true.

W opublikowanym kodzie nie ma możliwości TryRemovepowrotu, falseponieważ cdjest to zmienna lokalna, do której nie można uzyskać dostępu nigdzie indziej. Ale jeśli jakiś kod w innym miejscu miałby odniesienie do tego ConcurrentDictionaryobiektu i usuwał klucze w oddzielnym wątku, to możliwe, że TryRemovemoże powrócić false, nawet tutaj - ale tylko dlatego, że klucz został już usunięty , a nie dlatego, że wykonywana jest inna akcja słownik i klucz jakoś tam „utknęły”.

Dan Tao
źródło
5

ConcurrentDictionary nie cierpi na warunkach wyścigowych. Dlatego go używasz.

Wartość zwracana

prawda, jeśli obiekt został pomyślnie usunięty; w przeciwnym razie fałsz.

Mitch Wheat
źródło
2

Jeszcze jedna uwaga:

// This might fail if another thread is adding with key value of 1.
cd.TryAdd(1, "one"); 

Ten komentarz jest niepoprawny i prawdopodobnie zawiera to samo błędne przekonanie, co to znaczy „spróbować”. Nie chodzi o jednoczesną próbę dodania, chodzi o to, czy wartość została już dodana za pomocą klucza 1.

Rozważ standard Dictionary<TKey,TValue>. Odpowiedni kod to:

if (!d.Contains(1))
    d.Add(1, "one");

Wymaga to dwóch operacji. Nie ma możliwości zaprojektowania takiego interfejsu API, aby był bezpieczny dla wątków, ponieważ cdmoże mieć wartość z kluczem 1dodanym między wywołaniem do Containsi Add, co spowodowałoby Addrzucanie.

Współbieżne kolekcje mają interfejsy API, które logicznie łączą te pary test i wykonaj w pojedyncze operacje atomowe za jednym interfejsem API.

Drew Noakes
źródło