2011-11-22 21 views
58

Estoy en lo cierto al pensar que esto es el uso correcto de un Diccionario concurrenteDiccionario concurrente Uso correcto

private ConcurrentDictionary<int,long> myDic = new ConcurrentDictionary<int,long>(); 

//Main thread at program startup 

for(int i = 0; i < 4; i++) 
{ 
    myDic.Add(i, 0); 
} 

//Seperate threads use this to update a value 

myDic[InputID] = newLongValue; 

no tengo cerraduras, etc y sólo estoy actualizando el valor en el diccionario pesar de que múltiples hilos pueden estar tratando de hacer lo mismo.

+2

Depende - Qué 'newLongValue' depende del valor previo de' MYDIC [InputID] '? –

+74

1UP para el nombre de la variable "myDic"! –

+2

debe evitar acceder directamente por la tecla 'myDic [InputID]' para la condición de carrera. Deberías probar con 'GetOrAdd' –

Respuesta

52

Depende de lo que quiere decir con seguridad de subprocesos.

De MSDN - How to: Add and Remove Items from a ConcurrentDictionary:

ConcurrentDictionary<TKey, TValue> está diseñado para escenarios de multiproceso. No tiene que usar bloqueos en su código para agregar o eliminar elementos de la colección. Sin embargo, siempre es posible que un subproceso recupere un valor y otro subproceso para actualizar inmediatamente la colección al darle un valor nuevo a la misma clave.

lo tanto, es posible obtener una vista inconsistentes del valor de un elemento en el diccionario.

+1

¡Ese es un punto interesante! ¿Todavía usarías un candado en ese escenario? – Jon

+0

@Jon - Depende de su aplicación y si eso está bien lo hará. Pero yo diría que si quieres vistas consistentes de los elementos, necesitarías ajustar cada lectura y actualización de un elemento en un candado. – Oded

+4

Creo que esto no es lo que dice el documento. La incoherencia tiene que ver con lo que contiene la vista, si la vista es solo el valor, entonces es perfectamente consistente.Siempre que obtenga el valor de una clave, el valor de la clave en el diccionario podría cambiar. Esto es tan inconsistente como el valor de DateTime.Now. –

2

Sí, tienes razón.

Eso y la posibilidad de enumerar el diccionario en un hilo mientras se lo cambia en otro hilo son los únicos medios de existencia para esa clase.

+7

Lo que tendría que agregar es que [aquí] (http://blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx) es información útil de cómo y cuándo usar ' ConcurrentDictionary'. –

1

La mejor manera de averiguarlo es consultar la documentación de MSDN.

Para ConcurrentDictionary la página es http://msdn.microsoft.com/en-us/library/dd287191.aspx

En virtud del artículo hilo de seguridad, se afirma "Todos los miembros públicos y protegidos de ConcurrentDictionary (De TKey, TValue) son hilos de proceso seguro y pueden ser utilizados simultáneamente desde varios subprocesos."

Por lo tanto, desde el punto de vista de concurrencia usted está bien.

0

Depende, en mi caso prefiero usar este método.

ConcurrentDictionary<TKey, TValue>.AddOrUpdate Method (TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>); 

Consulte MSDN Library para ver los detalles del uso del método.

Ejemplo de uso:

results.AddOrUpdate(
    Id, 
    id => new DbResult() { 
    Id = id, 
    Value = row.Value, 
    Rank = 1 
    }, 
    (id, v) => 
    { 
    v.Rank++; 
    return v; 
    }); 
+1

FYI: "Cuando se suministra un método de valor de fábrica (a los métodos GetOrAdd y AddOrUpdate), en realidad se puede ejecutar y se puede descartar posteriormente (porque otro hilo ganó la carrera)". Más información aquí: https://arbel.net/2013/02/03/best-practices-for-using-concurrentdictionary/ – keremispirli

+0

Sí, tiene razón, como se señala en la sección de observaciones "Si llama a AddOrUpdate simultáneamente en diferentes subprocesos, addValueFactory se puede llamar varias veces, pero su par de clave/valor no se puede agregar al diccionario para cada llamada ". Por lo tanto, debe asegurarse de no generar múltiples objetos persistentes. – Onur

+0

Y si necesita actualizar el contenido, sin cambiar por completo el objeto almacenado, por ejemplo, para cambiar una propiedad de un objeto agregado anteriormente, este método es útil; de lo contrario, necesitará usar bloqueos u otros métodos de sincronización. – Onur