Indice di eccezione quando si utilizza gamma parallela per ciclo
-
25-09-2019 - |
Domanda
Sto cercando di eseguire il codice seguente ed io continuo a ricevere un Indice di eccezione gamma quando si cerca di valori di matrice assegnare alla lista: -
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]));
sto facendo qualcosa di sbagliato qui? Capisco che il processo è non ordinata / asincrona, ma perché "i" ottengo valori che sono superiori al valore di "Array.length"?
Soluzione
Il problema è che non si può chiamare List.Add()
contemporaneamente su più thread. Se avete bisogno di thread-safe collezioni, vedere lo spazio dei nomi System.Collections.Concurrent
.
Se si interrompe nel debugger quando si ottiene un'eccezione, vedrai che i
è non maggiore di array.Length
, ma è invece una potenza di 2 che è sostanzialmente inferiore array.Length
. Succede che il List
inizia con una matrice vuota di qualcosa come 4 elementi. Ogni volta che si aggiunge un elemento a una lista i cui gamma è piena, si crea una serie di due volte la lunghezza della vecchia matrice, copia i vecchi elementi ad esso, e memorizza il nuovo array.
Ora diciamo che l'elenco è fino a 31 elementi (il che significa che ha spazio per un altro) e due thread tenta di aggiungere un elemento di 32 °. Essi saranno entrambi eseguire codice in questo modo:
if (_size == _items.Length)
{
EnsureCapacity(_size + 1);
}
_items[_size++] = item;
In primo luogo essi saranno entrambi vedere che _size
(31) non è _items.Length
(32), in modo che entrambi eseguono _size++
. Il primo thread otterrà 31 (il corretto indice dell'elemento 32 °) e cambio _size
a 32. Il secondo filo otterrà 32 e provare a indicizzare _items[32]
, che vi dà il vostro un'eccezione perché si sta cercando di accedere all'elemento 33 ° di un 32- elemento dell'array.