2010-10-24 58 views
6

我想执行以下代码,我不断收到指数超出范围的异常试图数组分配值列表时: -索引超出范围例外的for循环

 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”的值高呢?

回答

15

问题是,您不能在多个线程上同时调用List.Add()。如果您需要线程安全的集合,请参阅System.Collections.Concurrent命名空间。

如果中断调试程序时,你会得到一个异常,你会看到iarray.Length更大,但不是2的幂实质上小于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并尝试索引_items[32],这会给您带来例外,因为它试图访问32位元素的第33个元素,元素数组。

+2

优秀的答案。我希望我可以投它两次。我将在我的下一篇博客文章中引用它;我希望你不介意。 – 2010-12-17 11:54:10

+0

+1很棒的答案,谢谢gabe! – andy 2012-11-08 23:32:52