启动新线程时抛出IndexOutOfRangeException

时间:2011-10-23 17:40:18

标签: c# multithreading lambda indexoutofboundsexception

当我运行以下代码段时,抛出IndexOutOfRangeException。当抛出异常时,我似乎是2。我的理解是新的线程在i的值被更改之后启动。有没有办法让这段代码免受此类问题的影响?

int x[2] = {1, 3};
int numberOfThreads = 2;

for (int i = 0; i < numberOfThreads; i++)
{
    new Thread(() =>
    {
        DoWork(x[i]);
    }).Start();
}

2 个答案:

答案 0 :(得分:6)

问题是正在捕获变量 i,并且当线程实际开始时,它是2。

请改用:

for (int i = 0; i < numberOfThreads; i++)
{
    int value = x[i];
    new Thread(() => DoWork(value)).Start();
}

或者:

foreach (int value in x)
{
    int copy = value;
    new Thread(() => DoWork(copy)).Start();
}

或者:

for (int i = 0; i < numberOfThreads; i++)
{
    int copyOfI = i;
    new Thread(() => DoWork(x[copyOfI])).Start();
}

在每种情况下,lambda表达式将在循环的每次迭代中捕获一个新变量 - 一个变量,将不会被后续迭代更改。

通常,您应该避免在稍后将执行的lambda表达式中捕获循环变量。有关详细信息,请参阅主题Eric Lippert's blog post

从C#5开始,可能会更改foreach循环行为以避免这是一个问题 - 但for循环等效仍然是一个问题。

答案 1 :(得分:2)

您正在关闭循环变量,以获取i当前值,而不是使用本地副本:

for (int i = 0; i < numberOfThreads; i++)
{
    int localI = i;
    new Thread(() =>
    {
        DoWork(x[localI]);
    }).Start();
}