For Loop result in Overflow with Task.Run or Task.Start

In 2021, You should really just use the built in Parallel.For for this. It's quite simple to achieve your desired effect:

ConcurrentBag<byte[]> results = new ConcurrentBag<byte[]>();

ParallelLoopResult result = Parallel.For(0, 4, (i, state) => {
   results.Add(GetData(i, plcPool[i]));
});

It's probably caused by a closure problem.

Try this:

 for (int i = 0; i < 4; i++)
 {
      //start task with current connection
      int index = i;
      tasks[index] = Task<byte[]>.Run(() => GetData(index, plcPool[index]));
 }

What is probably happening is that when the last thread starts running, the loop has already incremented i to 4, and that's the value that gets passed to GetData(). Capturing the value of i into a separate variable index and using that instead should solve that issue.

As an example, if you try this code:

public static void Main()
{
    Console.WriteLine("Starting.");

    for (int i = 0; i < 4; ++i)
        Task.Run(() => Console.WriteLine(i));

    Console.WriteLine("Finished. Press <ENTER> to exit.");
    Console.ReadLine();
}

it will often give you this kind of output:

Starting.
Finished. Press <ENTER> to exit.
4
4
4
4

Change that code to:

public static void Main()
{
    Console.WriteLine("Starting.");

    for (int i = 0; i < 4; ++i)
    {
        int j = i;
        Task.Run(() => Console.WriteLine(j));
    }

    Console.WriteLine("Finished. Press <ENTER> to exit.");
    Console.ReadLine();
}

and you get something like

Starting.
Finished. Press <ENTER> to exit.
0
1
3
2

Note how it is STILL NOT NECESSARILY IN ORDER! You will see all the correct values printed out, but in an indeterminate order. Multithreading is tricksy!

Tags:

C#

Task