C#从循环启动线程会引发IndexOutOfBoundsException

C#从循环启动线程会引发IndexOutOfBoundsException,c#,multithreading,C#,Multithreading,这很奇怪,因为很明显循环条件永远不会导致异常 Thread [] threads = new Thread[threadData.Length]; for (int i = 0; i < threadData.Length; i++) { threads[i]= new System.Threading.Thread(() => threadWork(threadData[i])); threads[i].Start(); } Thread[]threads=新线程[t

这很奇怪,因为很明显循环条件永远不会导致异常

Thread [] threads = new Thread[threadData.Length];
for (int i = 0; i < threadData.Length; i++)
{
   threads[i]= new System.Threading.Thread(() => threadWork(threadData[i]));
   threads[i].Start();
}
Thread[]threads=新线程[threadData.Length];
对于(int i=0;ithreadWork(threadData[i]);
线程[i].Start();
}

它只会导致线程数据的IndexOutOfBoundsException[i]

这是循环捕获的正常问题-您已经捕获了循环变量,因此在线程实际启动时,
i
是最终值,它是数组中的无效索引。解决方案是在循环内创建一个新变量,并捕获该变量:

Thread[] threads = new Thread[threadData.Length];
for (int i = 0; i < threadData.Length; i++)
{
    int copy = i;
    threads[i]= new System.Threading.Thread(() => threadWork(threadData[copy]));
    threads[i].Start();
}
或者使用直接的foreach循环,在运行时启动每个线程:

List<Thread> threads = new List<Thread>();
foreach (var data in threadData)
{
    var dataCopy = data;
    Thread thread = new Thread(() => ThreadWork(dataCopy));
    thread.Start();
    threads.Add(thread);
}
List threads=newlist();
foreach(threadData中的var数据)
{
var-dataCopy=数据;
线程线程=新线程(()=>ThreadWork(dataCopy));
thread.Start();
线程。添加(线程);
}

您捕获了循环变量
i
,当每个线程最终执行并从
threadData
检索数据时,可能会使用最后一个“i”值。将
i
分配给循环中的一个变量,并使用该变量,例如:

Thread [] threads = new Thread[threadData.Length];

for (int i = 0; i < threadData.Length; i++)
{
    int index = i;
    threads[i]= new System.Threading.Thread(() => threadWork(threadData[index]));
    threads[i].Start();
}
这里我们可以看到
VarI
被用来代替
i
。不明显的副作用是,当线程执行时,它们都会看到一个共享值,即
VarI
。如果线程在循环完成后启动,它们都将看到
i
的最大值


解决方法是将
i
赋值给循环中的一个临时变量,如第一个代码示例所述。

谢谢Jon,我为第一个回答的人标记了正确答案。@deadlock:实际上你没有。。。我在chibacity之前稍微回答了一下,但没关系:)@Jon:是的,我错了。正确答案适合你,乔恩。@Jon该死的飞碟!添加额外的细节是浪费时间。:)@chibacity:请从我这里获得+1:)
Thread [] threads = new Thread[threadData.Length];

for (int i = 0; i < threadData.Length; i++)
{
    int index = i;
    threads[i]= new System.Threading.Thread(() => threadWork(threadData[index]));
    threads[i].Start();
}
    private class LambdaHelper
    {
        public int VarI { get; set; }
    }

    private static void SomeMethod()
    {
        LambdaHelper helper = new LambdaHelper();

        Thread[] threads = new Thread[threadData.Length];

        for (helper.VarI = 0; helper.VarI < data.Length; helper.VarI++)
        {
          threads[helper.VarI] = new Thread(() => ThreadWork(data[helper.VarI]));
          threads[helper.VarI].Start();
        }
    }