2010-10-24 29 views
6

Estoy tratando de ejecutar el código siguiente y sigo obteniendo un índice fuera de excepción rango cuando se trata de asignar valores de la matriz a la lista: -índice fuera de excepción rango cuando se utiliza en paralelo para bucle de

 int[] array = new int[1000000]; 
     for (int i = 0; i < array.Length; i++) 
     { 
      array[i] = i; 
     } 

     List<int> list = new List<int>(); 
     Parallel.For(0, array.Length, i => list.Add(array[i])); 

Am Estoy haciendo algo mal aquí? Entiendo que el proceso no está ordenado/es asíncrono, pero ¿por qué "i" obtiene valores que son más altos que el valor de "array.Length"?

Respuesta

15

El problema es que no puede llamar al List.Add() al mismo tiempo en varios subprocesos. Si necesita colecciones seguras para hilos, consulte el espacio de nombres System.Collections.Concurrent.

Si se rompe en el depurador cuando recibe una excepción, se verá que es i no mayor que array.Length, sino que es una potencia de 2 que es sustancialmente menor que array.Length. Lo que sucede es que el List comienza con una matriz vacía de algo así como 4 elementos. Cada vez que agrega un elemento a una lista cuya matriz está llena, crea una matriz de dos veces la longitud de la matriz anterior, copia los elementos antiguos en ella y almacena la nueva matriz.

Ahora digamos que su lista es de hasta 31 elementos (lo que significa que tiene espacio para uno más) y dos hilos intentan agregar un 32º elemento. Serán tanto ejecutar código como este:

if (_size == _items.Length) 
{ 
    EnsureCapacity(_size + 1); 
} 
_items[_size++] = item; 

En primer lugar se va a ver que tanto _size (31) no es _items.Length (32), por lo que ambos ejecutar _size++. El primer subproceso obtendrá 31 (el índice correcto del 32º elemento) y cambiará a _size por 32. El segundo subproceso tendrá 32 e intentará indexar _items[32], lo que le ofrece su excepción porque está intentando acceder al 33º elemento de un 32- elemento de matriz.

+2

Excelente respuesta. Ojalá pudiera votarlo dos veces. Voy a hacer referencia a esto en mi próxima publicación de blog; Espero que no te moleste. –

+0

+1 gran respuesta genial, gracias gabe! – andy

Cuestiones relacionadas