Reputation: 383
I'm creating System.Threading.Tasks
from within a for loop, then running a ContinueWith
within the same loop.
int[,] referencedArray = new int[input.Length / 4, 5];
for (int i = 0; i <= input.Length/4; i += 2048)
{
int[,] res = new int[input.Length / 4, 5];
int[,] arrayToReference = new int[input.Length / 4, 5];
Array.Clear(arrayToReference, 0, arrayToReference.Length);
Array.Copy(input, i, arrayToReference, 0, input.Length / 4);
Task<Tuple<int[,], int>> test = Task.Factory.StartNew(() => addReferences(arrayToReference, i));
test.ContinueWith(t => { Array.Copy(t.Result.Item1, 0, referencedArray, t.Result.Item2, input.Length / 4); MessageBox.Show("yai", t.Result.Item2.ToString()); });
Array.Copy(res, 0, referencedArray, i, input.Length / 4);
where the addReference sbroutine is:
public Tuple<int[,],int> addReferences(int[,] input, int index)
{
for (int i = 0; i < 2048; i++)
{
for (int j = 0; j < i; j++)
{
if ((input[i, 0] == input[j, 0]) && (input[i, 1] == input[j, 1]) && (input[i, 2] == input[j, 2]) && (input[i, 3] == input[j, 3]))
{
input[i, 4] = (j - i);
}
}
}
}
return new Tuple<int[,],int>(input,index);
}
However, I am getting really strange results:
1.The index (generated from the loop counter when the task is started) somehow becomes too large. I initially thought that this was because the loop counter had incremented past its maximum, stopping the loop, but when the continueWith
executed it used the new value. However, even when I send the loop counter's value to the task as index
when it starts, the error persists. Edit: Solved
I made I mistake in the original count
2.For some reason fewer than expected tasks are actually completed (e.g. even though 85 tasks are expected to be created, based on a loop counter maximum of 160,000 divided by a iteration of 2,048 = 78, only 77 pop ups appeared) - Edit Checking the console, it's apparent that the loop counter got up until about 157,696 before suddenly stopping.
I'm really confused by Tasks and Threading, so if you could be of any assistance that would be really useful - thanks in advance.
Edit I've made the changes suggested by Douglas, which solved my first problem - I'm still stuck on the second.
Upvotes: 3
Views: 264
Reputation: 54887
This might not completely resolve the issues you're having, but as a starting point, you need to avoid the closure issue by copying your loop counter to an inner variable before referencing it in your anonymous method:
for (int i = 0; i <= input.Length/4; i += 2048)
{
// ...
int iCopy = i;
var test = Task.Factory.StartNew(() => addReferences(arrayToReference, iCopy));
// ...
}
See Jon Skeet's answer (particularly the linked article) for an explanation of why this is necessary.
Edit: Regarding your second problem, I suspect it might have to do with integer division. What is the value of input.Length
for which you're expecting 85 iterations? You say that 174,000 divided by 2,048 should give 85, but in practice, it will give 84, since integer division causes results to be truncated.
Edit2: Another reason you're not seeing all expected iterations could be that your program is terminating without waiting for the tasks (which typically execute on background threads) to complete. Check whether waiting on the tasks resolves your issue:
List<Task> tasks = new List<Task>();
for (int i = 0; i <= input.Length/4; i += 2048)
{
// ...
var test = Task.Factory.StartNew(() => addReferences(arrayToReference, iCopy));
tasks.Add(test);
// ...
}
Task.WaitAll(tasks);
Upvotes: 4