Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused about multi-threading in a loop for C# [duplicate]

Possible Duplicate:
C# Captured Variable In Loop

I am pretty new to multi-threading programming. When I ran the code below and only the last child got executed. Can some one tell me what happened? Thank you very much.

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() + "]");
    }
}

Output


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]
like image 601
Dreteh Avatar asked Mar 08 '12 07:03

Dreteh


2 Answers

By using the loop variable in your lambda, all of the effectively refer to the same variable, which is the last item of your dictionary at the time they run.

You need to assign the loop variable to another variable local to the loop before passing it to a lambda. Do this:

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: It seems this little pitfall is fixed in C#5. That's why it might work for others ;) See comment by labroo

like image 74
Botz3000 Avatar answered Oct 31 '22 05:10

Botz3000


You can prevent that behavior by assigning kvp to a local variable in the for loop and pass the variables fields Key and Value to the DoSomething method.

like image 25
saintedlama Avatar answered Oct 31 '22 04:10

saintedlama