6

次のコードを実行しようとしていますが、配列の値をリストに割り当てようとすると、Index out of range 例外が発生し続けます:-

        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]));

ここで何か間違っていますか?プロセスが順序付けられていない/非同期であることは理解していますが、「i」が「array.Length」の値よりも大きい値を取得するのはなぜですか?

4

1 に答える 1

19

List.Add()問題は、複数のスレッドで同時に呼び出すことができないことです。スレッド セーフなコレクションが必要な場合は、System.Collections.Concurrent名前空間を参照してください。

例外が発生したときにデバッガーに割り込むと、 がよりも大きくなくより大幅に小さい 2 の累乗であることiがわかります。何が起こるかというと、は 4 つの要素のような空の配列から始まります。配列がいっぱいになっているリストに要素を追加すると、古い配列の 2 倍の長さの配列が作成され、古い要素がそこにコピーされ、新しい配列が格納されます。array.Lengtharray.LengthList

ここで、リストが最大 31 個の要素 (つまり、もう 1 個分のスペースがあることを意味します) であり、2 つのスレッドが 32 番目の要素を追加しようとしているとします。どちらも次のようなコードを実行します。

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

まず、両方とも_size(31) が_items.Length(32) ではないことがわかるため、両方とも を実行し_size++ます。最初のスレッドは 31 (32 番目の要素の正しいインデックス) を_size取得し、32 に変更され_items[32]ます。 .

于 2010-10-24T05:05:37.563 に答える