Запуск потока из цикла и передача идентификатора цикла - PullRequest
1 голос
/ 15 сентября 2009

Я только сегодня начал играть с многопоточностью и столкнулся с чем-то, чего я не понимаю.

public void Main()
{ 
    int maxValue = 5;
    for (int ID = 0; ID < maxValue; ID++)
    {
        temp(ID);
    }
}

public void temp(int i)
{
    MessageBox.Show(i.ToString());
}

Базовая, которая работает нормально, но когда я пытаюсь создать новый поток для каждого, он пропускает только maxValue. Пожалуйста, не обращайте внимания на то, как это плохо, я написал это только в качестве упрощенного примера.

public void Main()
{ 
    int maxValue = 5;
    for (int ID = 0; ID < maxValue; ID++)
    {
        threads.Add(new Thread(() => temp(myString, rowID)));
        threads[rowID].Start();
    }
}

public void temp(string myString, int i)
{
    string _myString = myString;

    MessageBox.Show(i.ToString());
}

Учитывая это, у меня есть два вопроса: 1) Почему метод не вызывается в новом потоке, передающем идентификатор? 2) Как это правильно кодировать?

1 Ответ

9 голосов
/ 15 сентября 2009

Проблема в том, что у вас есть только одна переменная ID, и она записывается. Переменная имеет значение read только когда код в новом потоке фактически выполняется, что часто происходит после того, как ваш основной поток завершил свой цикл, оставляя ID в maxValue. Сделайте копию на каждой итерации цикла, чтобы каждый раз захватывать разные переменные:

for (int ID = 0; ID < maxValue; ID++)
{
    int copy = ID;
    threads.Add(new Thread(() => temp(myString, copy)));
    threads[rowID].Start();
}

Это распространенная ошибка с замыканиями. Прочитайте мою статью, сравнивающую закрытия C # и Java для получения дополнительной информации. Кстати, то же самое происходит с foreach - и это еще более запутанно, поскольку читает , как будто вы каждый раз получаете новую переменную:

foreach (string url in urls)
{
    // Aargh, bug! Don't do this!
    new Thread(() => Fetch(url)).Start();
}

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

foreach (string url in urls)
{
    string urlCopy = url;
    new Thread(() => Fetch(urlCopy)).Start();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...