How can I keep track of how many async tasks have completed in a loop?
c#, c#-4.0, multithreading, task, task-parallel-library
Solution
You get mixed output, because counter is not incremented in the same order as `Debug.WriteLine(...)` method is executed.
To get a consistent progress report, you can introduce a reporting lock into the task
tasks.Add(
Task.Factory.StartNew(() =>
{
Debug.WriteLine("Exporting " + valueParam );
System.Threading.Thread.Sleep(500);
lock(progressReportLock)
{
counter++;
StatusMessage = string.Format("Exporting {0} / {1}", counter, count);
Debug.WriteLine("Finished " + counter.ToString());
}
})
);
Problem
I have some code that loops through a list of records, starts an export task for each one, and increases a progress counter by 1 each time a task finishes so the user knows how far along the process is. But depending on the timing of my loops, I often see the output showing a higher number before a lower number. For example, I would expect to see output like this: ``` Exporting A Exporting B Exporting C Exporting D Exporting E Finished 1 / 5 Finished 2 / 5 Finished 3 / 5 Finished 4 / 5 Finished 5 / 5 ``` But instead I get output like this ``` Exporting A Exporting B Exporting C Exporting D Exporting E Finished 1 / 5 Finished 2 / 5 Finished 5 / 5 Finished 4 / 5 Finished 3 / 5 ``` I don't expect the output to be exact since I'm not locking the value when I update/use it (sometimes it outputs the same number twice, or skips a number), however I wouldn't expect it to go backwards. My test data set is 72 values, and the relevant code looks like this: ``` var tasks = new List<Task>(); int counter = 0; StatusMessage = string.Format("Exporting 0 / {0}", count); foreach (var value in myValues) { var valueParam = value; // Create async task, start it, and store the task in a list // so we can wait for all tasks to finish at the end tasks.Add( Task.Factory.StartNew(() => { Debug.WriteLine("Exporting " + valueParam ); System.Threading.Thread.Sleep(500); counter++; StatusMessage = string.Format("Exporting {0} / {1}", counter, count); Debug.WriteLine("Finished " + counter.ToString()); }) ); } // Begin async task to wait for all tasks to finish and update output Task.Factory.StartNew(() => { Task.WaitAll(tasks.ToArray()); StatusMessage = "Finished"; }); ``` The output can appear backwards in both the debug statements and the `StatusMessage` output. What's the correct way to keep count of how many async tasks in a loop are completed so that this problem doesn't occur?