got a Problem, hope someone can help me out.
i try to start 4 Task in an Loop but im getting an ArgumentOutOfRangeException:
for (int i = 0; i < 4; i++)
{
//start task with current connection
tasks[i] = Task<byte[]>.Run(() => GetData(i, plcPool[i]));
}
The Loop gets an Overflow because i = 4
if i start the Tasks without a Loop, they run without any Problems:
tasks[0] = Task<byte[]>.Run(() => GetData(0, plcPool[0]));
tasks[1] = Task<byte[]>.Run(() => GetData(1, plcPool[1]));
tasks[2] = Task<byte[]>.Run(() => GetData(2, plcPool[2]));
tasks[3] = Task<byte[]>.Run(() => GetData(3, plcPool[3]));
dont know why? The Tasks GetData from a Siemens PLC via Socket Connection. The PLC Supports up to 32 Connections. I receive 200 Bytes per Connection.
private byte[] GetData(int id, PLC plc)
{
switch (id)
{
case 0:
return plc.ReadBytes(DataType.DataBlock, 50, 0, 200);
case 1:
return plc.ReadBytes(DataType.DataBlock, 50, 200, 200);
case 2:
return plc.ReadBytes(DataType.DataBlock, 50, 500, 200);
case 3:
return plc.ReadBytes(DataType.DataBlock, 50, 700, 200);
case 4:
return plc.ReadBytes(DataType.DataBlock, 50, 900, 117);
default:
return null;
}
}
any idea?
Regards Sam
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With