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.
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. –
+1 très bonne réponse, merci gabe! – andy