C# Task.WhenAll not triggering next task

I'm new to multi-tasking, however I'm trying to learn how it all works. I have the following code, which I thought would create a task and run the performInitialLoad method, and when that completes, would then fire off the initializeDataHarvester method. The performInitialLoad works fine, and it does reach the bottom of the method because I can see the text "Initial tag data load complete" in my console. But it never seems to fire the initializeDataHarvester method. Any ideas?

private void mainTaskLoader() {
     Task initialLoad = new Task(performInitialTagLoad);
     initialLoad.Start();
     Task dataHarvester = new Task(() => {
          Task.WhenAll(initialLoad);
     }).ContinueWith(t => initializeDataHarvester());         
}

private void performInitialTagLoad() {
   allTags = globals.getTags();
   foreach (KeyValuePair<String, String> tag in allTags) {
       try {
           globals.insertUpdateHarvesterData(tag.Key.ToString(), commObject.Read(tag.Value.ToString()));
       } catch (Exception e) {
           Console.WriteLine("Error on initial load: " + e.Message, true);                    
       }
   }
   Console.WriteLine("Initial tag data load complete");         
}

private void initializeDataHarvester() {
        Console.WriteLine("Got here!");            
}
Jon Skeet
people
quotationmark

Task.WhenAll returns immediately - but it returns a task which will complete when the tasks have completed. You're ignoring that return value at the moment. You're also not starting the task which calls WhenAll, which is why that task is never completing.

You could just use:

Task.WhenAll(initialLoad).ContinueWith(...);

... but better yet, you could just avoid using WhenAll at all, given that you've only got a single task anyway.

You should also:

  • Learn about async/await, which makes a lot of things much easier
  • Start following .NET naming conventions

With async/await, this code would be something like:

private async Task MainTaskLoader()
{
    await Task.Run(PerformInitialTagLoad);
    InitializeDataHarvester();
}

If you genuinely have multiple things to run, you could use:

private async Task MainTaskLoader()
{
    var task1 = Task.Run(PerformInitialTagLoad);
    var task2 = Task.Run(SomethingElse);
    // Imagine we have many of these...
    await Task.WhenAll(task1, task2);
    InitializeDataHarvester();
}

Ideally, you'd make PerformInitialTagLoad an async method as well, mind you - which would require making the insertion async too.

people

See more on this question at Stackoverflow