¿Cuándo ConcurrentDictionary TryRemove devolverá falso?

79

¿Solo devolverá falso si el diccionario no contiene un valor para la clave dada o también devolverá falso debido a las condiciones de carrera del hilo, como si otro hilo agrega / actualiza algo?

Pregunta en código:

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

Editar: Creo que solo devolverá falso si no contiene un valor para la clave dada, pero quiero estar absolutamente seguro.

Martin Ingvar Kofoed Jensen
fuente

Respuestas:

85

Si bien Mitch tiene razón en que ConcurrentDictionaryno es vulnerable a las condiciones de carrera, creo que la respuesta a la pregunta que hace es que sí, si la clave está presente, TryRemovefuncionará y volverá true.

En el código que publicó, no hay forma de que TryRemoveregrese, falseya que cdes una variable local a la que no se accede en ningún otro lugar. Pero si a algún código en otro lugar se le dio una referencia a este ConcurrentDictionaryobjeto y estuviera eliminando claves en un hilo separado, entonces es posible que TryRemovepueda regresar false, incluso aquí, pero solo porque la clave ya se eliminó , no porque se esté realizando alguna otra acción en el diccionario y la clave de alguna manera están "atascados" allí.

Dan Tao
fuente
5

El ConcurrentDictionary no sufre condiciones de carrera. Por eso lo usas.

Valor devuelto

Es verdadero si un objeto se eliminó con éxito; de lo contrario, falso.

Trigo Mitch
fuente
2

Otro punto a destacar:

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

Este comentario es incorrecto y posiblemente sufre el mismo concepto erróneo sobre lo que significa "intentar". No se trata de un intento simultáneo de agregar, es si ya se ha agregado un valor con la clave 1.

Considere un estándar Dictionary<TKey,TValue>. El código equivalente sería:

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

Esto requiere dos operaciones. No hay forma de diseñar una API de este tipo para que sea segura para subprocesos, ya que cdpodría tener un valor con una clave 1agregada entre la llamada a Containsy Add, lo que luego resultaría en un Addlanzamiento.

Las colecciones concurrentes tienen API que agrupan lógicamente estos pares de prueba y ejecución en operaciones atómicas únicas, detrás de una única API.

Dibujó Noakes
fuente