Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tasks in array -- only last one runs

Tags:

c#

I was experimenting with tasks. Why does this output 10 and not each value of the loop?

public static void StartTasks()
{
    Task[] tasks = new Task[10];
    for (int i = 0; i < 10; i++)
        tasks[i] = new Task(() => Console.WriteLine(i));

    foreach (Task task in tasks)
    {
        task.Start();                       
    }       
}
like image 256
Marty Avatar asked Dec 09 '12 03:12

Marty


2 Answers

C# lambdas capture a reference to the variable, not the value of the variable.

If you want to capture the value, you need to make a copy of it first inside the loop which causes the capture to get the reference to the locally scoped unchanging variable.

public static void StartTasks()
{
    Task[] tasks = new Task[10];
    for (int i = 0; i < 10; i++) {
        int j = i;
        tasks[i] = new Task(() => Console.WriteLine(j));
    }

    foreach (Task task in tasks)
    {
        task.Start();                       
    }       
}
like image 139
Donnie Avatar answered Nov 08 '22 06:11

Donnie


In addition to the accepted answer, you can also pass a parameter to the task. For example,

    using System;
    using System.Threading.Tasks;

    static void StartTasks(int instances)
    {
        var tasks = new Task[instances];
        for (int i = 0; i < instances; i++)
        {
            tasks[i] = new Task((object param) =>
            {
                var t = (int)param;
                Console.Write("({0})", t);
            }, i);
        }

        Parallel.ForEach<Task>(tasks, (t) => { t.Start(); }); 
        Task.WaitAll(tasks);
    }
like image 40
Alex Nolasco Avatar answered Nov 08 '22 08:11

Alex Nolasco