Смущает многопоточность в цикле для С#

Возможный дубликат:
С# Captured Variable In Loop

Я новичок в многопоточном программировании. Когда я запустил код ниже, и только последний ребенок был выполнен. Может кто-нибудь сказать мне, что случилось? Большое вам спасибо.

private void Process()
{
    Dictionary<int, int> dataDict = new Dictionary<int, int>();
    dataDict.Add(1, 2000);
    dataDict.Add(2, 1000);
    dataDict.Add(3, 4000);
    dataDict.Add(4, 3000);

    foreach (KeyValuePair<int, int> kvp in dataDict)
    {
        Console.WriteLine("Ready for [" + kvp.Key.ToString() + "]");
        Task.Factory.StartNew(() => DoSomething(kvp.Value, kvp.Key));
    }

private static void DoSomething(int waitTime, int childID)
{
    {               
        Console.WriteLine("Start task [" + childID.ToString() + "]");
        Thread.Sleep(waitTime);
        Console.WriteLine("End task [" + childID.ToString() + "]");
    }
}

Выход


Ready for [1]
Ready for [2]
Ready for [3]
Ready for [4]
Start task [4]
Start task [4]
Start task [4]
Start task [4]
End task [4]
End task [4]
End task [4]
End task [4]

Ответ 1

Используя переменную цикла в вашей лямбда, все эффективно ссылаются на ту же переменную, которая является последним элементом вашего словаря в момент их запуска.

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

foreach (KeyValuePair<int, int> kvp in dataDict)
{
    var pair = kvp;
    Console.WriteLine("Ready for [" + pair.Key.ToString() + "]");
    Task.Factory.StartNew(() => DoSomething(pair.Value, pair.Key));
}

EDIT: Кажется, эта небольшая ошибка зафиксирована на С# 5. Вот почему он может работать для других;) См. Комментарий labroo

Ответ 2

Вы можете предотвратить это поведение, назначив kvp локальной переменной в цикле for и передайте поля переменных Key и Value методу DoSomething.