2013-07-21 26 views
2

我在循环中启动4个线程。每个线程获取对数组元素的引用以写入结果。在循环中传递数组元素的起始线程

但是,在我创建每个线程的线上,我得到了一个System.IndexOutOfRangeException。我很惊讶,指数“我”超出范围。

这里有一个例子:

void ThreadsStarter() 
{ 
    double[] data = new double[4]; 

    for(int i = 0; i < 4; i++) 
    { 
     Thread my_thread = new Thread(() => Work(data[i])); 
     my_thread.Start(); 
    } 
} 

void Work(double data) 
{ 
} 

为什么发生这种情况?

+2

您[[关闭循环变量]](http://blogs.msdn.com /b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx) – Blorgbeard

+0

我已经从您的示例/标题中删除了'ref'作为无关的问题 - 感觉自由编辑/回滚。注意'ref'通常很难使用/理解,特别是当您开始使用更灵活的集合时,例如'List '而不是'Array'。尽量避免使用'ref' - 即在这种情况下'Tuple.Create(data,i)'可能是一个选项(显然是在lambda之前创建的,以避免您现在遇到的问题)。 –

+0

谢谢。现在我也知道那个建筑的名字(闭合/ lambda)。我尽量避免参考。我会考虑使用元组,而这看起来更干净。这是一个很好的文章Blorgbeard。 – symbiont

回答

5

这是一个常见错误:当线程启动时,我得到评估,这发生在循环结束后。做一个临时工,分配给我,并使用温度,而不是我在你的拉姆达解决问题:

void ThreadsStarter() 
{ 
    double[] data = new double[4]; 

    for(int i = 0; i < 4; i++) 
    { 
     var temp = i; 
     Thread my_thread = new Thread(() => Work(ref data[temp])); 
     my_thread.Start(); 
    } 
} 

void Work(ref double data) 
{ 
} 
+0

谢谢。这是有效的 – symbiont

+0

这是有效的,因为当你重新创建一个临时变量时,编译器检测到闭包在每个循环过程中“附加”到一个不同的变量,并且会生成一个“** new ** DisplayClass()”代码封闭)在每个传球内。如果没有临时变量,它将在所有循环中使用相同的DisplayClass(其中包含i变量的成员)。 (类似于c#5为foreach循环生成的代码 - 请参阅示例[here](http://aakinshin.net/en/blog/dotnet/closures/#the-foreach-loop))。 – BornToCode