Когда ConcurrentDictionary TryRemove вернет false

Будет ли он возвращать false только в том случае, если словарь не содержит значения для данного ключа или он также будет возвращать false из-за условий гонки нитей, например, другой поток добавляет/обновляет что-то?

Вопрос в коде:

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); 

Edit: Я думаю, что он вернет false только в том случае, если он не содержит значения для данного ключа, но должен быть абсолютно уверен.

Ответ 1

В то время как Митч прав, что ConcurrentDictionary не уязвим для условий гонки, я думаю, что ответ на вопрос, который вы задаете, заключается в том, что да, если ключ присутствует, TryRemove будет работать и вернет true.

В коде, который вы отправили, нет способа вернуть TryRemove false, поскольку cd - это локальная переменная, не доступная нигде. Но если какой-то код в другом месте был дан ссылкой на этот объект ConcurrentDictionary и удалял ключи в отдельном потоке, тогда возможно, что TryRemove может возвращать false, даже здесь, но только потому, что ключ был уже удален, а не потому, что в словаре выполняется какое-то другое действие, и ключ каким-то образом "застревает" там.

Ответ 2

ConcurrentDictionary не страдает от условий гонки. Вот почему вы его используете.

Возвращаемое значение

true, если объект удален успешно; в противном случае - false.

Ответ 3

Еще один момент:

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

Этот комментарий неверен и, возможно, страдает от того же неправильного представления о том, что значит "попробовать". Это не о параллельной попытке добавить, то ли значение уже было добавлено с помощью клавиши 1.

Рассмотрим стандарт Dictionary<TKey,TValue>. Эквивалентным кодом будет:

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

Для этого требуется две операции. Нет никакого способа создать такой API, чтобы быть потокобезопасным, поскольку cd может иметь значение с ключом 1, добавленным между вызовом Contains и Add, которое затем приведет к металокации Add.

В параллельных коллекциях есть API-интерфейсы, которые логически объединяют эти тестовые пары в одиночные атомные операции за одним API.