IndexOutOfRangeException генерируется при запуске нового потока - PullRequest
1 голос
/ 23 октября 2011

Когда я запускаю следующий фрагмент кода, генерируется исключение IndexOutOfRangeException.Похоже, что мне 2, когда выдается исключение.Насколько я понимаю, новый поток запускается после изменения значения я.Есть ли способ обезопасить этот код от подобных проблем?

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

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

Ответы [ 2 ]

6 голосов
/ 23 октября 2011

Проблема в том, что переменная 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();
}

В каждом случае лямбда-выражение будет захватывать новую переменную на каждой итерации цикла - переменную, которая не будет изменяться при последующих итерациях.

В общем, вам следует избегать захвата переменной цикла в лямбда-выражении, которое будет выполнено позже. См. сообщение Эрика Липперта в блоге на эту тему для получения более подробной информации.

Начиная с C # 5, вполне вероятно, что поведение цикла foreach будет изменено, чтобы избежать этой проблемы, но эквивалент цикла for все равно будет проблемой.

2 голосов
/ 23 октября 2011

Вы закрываете переменную цикла, чтобы получить текущее значение из i, вместо этого используйте локальную копию:

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