2012-05-07 12 views
31

Tiene una pregunta sobre la seguridad de la rosca con ConcurrentDictionary. Desde la API, veo que el enumerador es seguro para subprocesos, pero no veo lo mismo para las propiedades de claves y valores. Mi pregunta es:La propiedad ConcurrentDictionary Keys o Values ​​threadsafe

¿Es seguro recorrer la colección Keys o Values cuando hay otros hilos que la modifican al mismo tiempo?

+1

El empadronador se comporta de forma diferente a las claves y valores pr operties. Si bien estos brindan una instantánea del diccionario en un momento dado, los contenidos devueltos por ['GetEnumerator'] (https://msdn.microsoft.com/en-us/library/dd287131.aspx) (que también se usan en Las consultas LINQ que utilizan el diccionario como fuente) contienen modificaciones realizadas en el diccionario después de que se llamó a 'GetEnumerator'. –

Respuesta

15

ConcurrentDictionary representa un colección rosca de seguridad de clave-valor pares que se puede acceder por múltiples hilos simultáneamente.

Fuente: MSDN

+4

+1, conciso! :) Además: sí, ambas propiedades están protegidas con un candado, lo que enumerará es el contenido del diccionario ** en el momento en que comenzó la enumeración ** (para que pueda ver una clave, por ejemplo, que ha sido eliminado de otro hilo). –

43

Aunque me gusta la documentación, que tienden a verificar las cosas con un pequeño programa en caso de duda o siento que podría estar asumiendo demasiado.

El siguiente código verifica que, de hecho, puede enumerar la colección de valores de forma segura al agregar o eliminar claves de un hilo separado al que está teniendo lugar la enumeración. Esto no causará que la colección habitual fuera excepciones modificadas. Con más detalle, aquí hay un par de casos de prueba

Caso 1: Enumeración Valores y eliminación de una clave

Si sigue la siguiente secuencia:

  • iniciar la enumeración de la colección de valores de una thread
  • eliminar una clave de un hilo diferente que no hemos enumerado todavía
  • Continuar enumerando en el subproceso original

El comportamiento observado es que la clave eliminada se enumerará ya que existía en la colección de valores cuando comenzamos la enumeración. No se levantará ninguna excepción.

Caso 2: Enumeración Valores y la adición de una clave

  • iniciar la enumeración de la colección de valores de un hilo
  • agregar una nueva clave de un hilo diferente que no hemos enumerado todavía
  • Continuar enumerar en el subproceso original

El comportamiento observado es que la clave agregada no se enumerará ya que d id no existe en la recopilación de valores cuando comenzamos a enumerarlo. No se planteará ninguna excepción ya sea que usemos TryAdd o agreguemos asignando directamente al diccionario, es decir, diccionario [clave] = valor.

Código de ejemplo

Este es el programa ejemplo que muestra dos casos:

ConcurrentDictionary<int, int> dictionary = new ConcurrentDictionary<int, int>(); 

// Seed the dictionary with some arbitrary values; 
for (int i = 0; i < 30; i++) 
{ 
    dictionary.TryAdd(i, i); 
} 

// Reader thread - Enumerate the Values collection 
Task.Factory.StartNew(
     () => 
     { 
      foreach (var item in dictionary.Values) 
      { 
       Console.WriteLine("Item {0}: count: {1}", item, dictionary.Count); 
       Thread.Sleep(20); 
      } 

     } 
); 

// writer thread - Modify dictionary by adding new items and removing existing ones from the end 
Task.Factory.StartNew(
     () => 
     { 
      for (int i = 29; i >= 0; i--) 
      { 
       Thread.Sleep(10); 
       //Remove an existing entry 
       int removedValue; 
       if (dictionary.TryRemove(i, out removedValue)) 
        Console.WriteLine("Removed item {0}", removedValue); 
       else 
        Console.WriteLine("Did not remove item {0}", i); 

       int iVal = 50 + i*2; 
       dictionary[iVal] = iVal; 
       Thread.Sleep(10); 
       iVal++; 
       dictionary.TryAdd(iVal, iVal); 
      } 
     } 
); 

Console.ReadKey(); 

Y aquí está la salida en modo de lanzamiento:

Console output

+1

Wish microsoft podría documentar esto en MSDN. – user664769

+11

Lo que realmente está diciendo es que las colecciones 'Keys' y' Values' son instantáneas del diccionario en el momento en que obtuvo el enumerador. Casi como si hicieran un clon profundo y se lo devolvieran a usted para que lo enumerara. –