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命名空间。

如果您在遇到异常时进入调试器,您会看到i不大于,而是array.Length2 的幂,大大小于array.Length。发生的事情是List从一个空数组开始,比如 4 个元素。每当您将元素添加到数组已满的列表时,它都会创建一个长度为旧数组两倍的数组,将旧元素复制到其中,并存储新数组。

现在假设您的列表最多包含 31 个元素(意味着它还有空间容纳一个),并且两个线程尝试添加第 32 个元素。它们都将执行如下代码:

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

首先他们都会看到_size(31) 不是_items.Length(32),所以他们都执行_size++. 第一个线程将获得 31 (第 32 个元素的正确索引)并更改_size为 32。第二个线程将获得 32 并尝试 index _items[32],这会给您异常,因为它试图访问 32 元素数组的第 33 个元素.

于 2010-10-24T05:05:37.563 回答