can anyone please tell me, how is it possible that this code:
for (byte i = 0; i < someArray.Length; i++)
{
pool.QueueTask(() =>
{
if (i > 0 && i < someArray.Length)
{
myFunction(i, someArray[i], ID);
}
});
}
falls on the line where myFunction is called with IndexOutOfRangeException because the i variable gets value equal to someArray.Length? I really do not understand to that...
Note: pool is an instance of simple thread pool with 2 threads.
Note2: The type byte in for loop is intentionally placed because the array length can not go over byte max value (according to preceding logic that creates the array) and I need variable i to be of type byte.
Your code is creating a closure on i, and it will end up being someArray.Length every time it's executed. The Action that you end up passing into QueueTask() retains the state of the for loop, and uses the value of i at execution time. Here is a compilable code sample that expresses this same problem,
static void Main(string[] args)
{
var someArray = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var fns = new List<Action>();
for (int i = 0; i < someArray.Length; i++)
{
fns.Add(() => myFunction(i, someArray[i]));
}
foreach (var fn in fns) fn();
}
private static void myFunction(int i, int v)
{
Console.WriteLine($"{v} at idx:{i}");
}
You can break this by copying the closed around variable in a local, which retains the value of i at creation time of the Action.
static void Main(string[] args)
{
var someArray = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var fns = new List<Action>();
for (int i = 0; i < someArray.Length; i++)
{
var local = i;
fns.Add(() => myFunction(local, someArray[local]));
}
foreach (var fn in fns) fn();
}
private static void myFunction(int i, int v)
{
Console.WriteLine($"{v} at idx:{i}");
}
Related reading: http://csharpindepth.com/Articles/Chapter5/Closures.aspx
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