2010-10-24 2 views
6

Je suis en train d'exécuter le code suivant et je continue à obtenir un indice hors d'exception plage lorsque vous essayez d'attribuer des valeurs de tableau à la liste: -Index hors exception de plage lors de l'utilisation en parallèle pour la boucle

 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 Je fais quelque chose de mal ici? Je comprends que le processus est non ordonné/asynchrone, mais pourquoi "i" obtient-il des valeurs supérieures à la valeur de "array.Length"?

Répondre

15

Le problème est que vous ne pouvez pas appeler simultanément List.Add() sur plusieurs threads. Si vous avez besoin de collections thread-safe, consultez l'espace de noms System.Collections.Concurrent.

Si vous cassez dans le débogueur lorsque vous obtenez une exception, vous verrez que i est pas supérieure à array.Length, mais est au contraire une puissance de 2 qui est sensiblement inférieure à array.Length. Qu'est-ce qui se passe est que le List commence avec un tableau vide de quelque chose comme 4 éléments. Chaque fois que vous ajoutez un élément à une liste dont le tableau est plein, il crée un tableau de deux fois la longueur de l'ancien tableau, y copie les anciens éléments et stocke le nouveau tableau.

Maintenant, disons que votre liste contient jusqu'à 31 éléments (ce qui signifie qu'elle a de l'espace pour un de plus) et que deux threads essaient d'ajouter un 32ème élément. Ils seront tous deux exécuter du code comme ceci:

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

D'abord, ils seront tous deux voir que _size (31) n'est pas _items.Length (32), donc ils ont tous deux exécuter _size++. Le premier thread obtiendra 31 (l'index correct du 32ème élément) et changera _size à 32. Le deuxième thread obtiendra 32 et essayera d'indexer _items[32], qui te donne votre exception parce qu'il essaie d'accéder au 33ème élément d'un 32- tableau d'éléments.

+2

Excellente réponse. J'aimerais pouvoir voter deux fois. Je vais faire référence à ceci sur mon prochain article de blog; J'espère que cela ne vous dérange pas. –

+0

+1 très bonne réponse, merci gabe! – andy

Questions connexes