How can I keep track of how many asynchronous tasks were completed in a loop?

I have a code that iterates over the list of records, starts the export task for each of them, and increments the execution counter by 1 each time the task ends, so the user knows how far the process has moved.

But depending on the time of my cycles, I often see that the result shows a larger number before a lower number.

For example, I would expect to see the output as follows:

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

, , / ( ), , .

- 72 , :

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";
});

, StatusMessage.

, ?

+5
2

, , Debug.WriteLine(...).

,

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());
        }
    })
);
+7

counter . ++ . , ,

  • push counter to stack
  • 1

, . , counter.

++

Interlocked.Increment(ref counter);

, . ,

, , . , , , . , , .

object lockTarget = new object();
int counter = 0; 

...

lock (lockTarget) {
  counter++;
  StatusMessage = string.Format("Exporting {0} / {1}", counter, count);
  Debug.WriteLine("Finished " + counter.ToString());
}

, counter , Interlocked.Increment

+5

All Articles