QuestionMaster
QuestionMaster

Reputation: 23

Continuation code (ContinueWith) not getting executed

I have the following code where the continuation code isn't getting executed.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Konsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main starting...");

            Task.Run(async () =>
            {
                await Job1();
            })
            .ContinueWith(async t =>
            {
                await Job2();
            }).Wait();

            Console.WriteLine("Main ending...");
        }

        public static async Task Job1()
        {
            await Task.Run(() =>
            {
                for (int i = 1; i <= 2; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Job1 {i}");
                }
            });
        }

        public static async Task Job2()
        {
            await Task.Run(() =>
            {
                for (int i = 1; i <= 2; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Job2 {i}");
                }
            });
        }
    }
}

Console output:

Main starting...
Job1 1
Job1 2
Main ending...

I expected Job2 to be executed as well before the application closed.

Upvotes: 2

Views: 298

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 456747

You should not use ContinueWith; it's a dangerous, low-level method. In this case, you're encountering a problem because ContinueWith does not understand asynchronous delegates.

Ideally, you should replace all calls to ContinueWith (and Wait) with await:

static async Task Main(string[] args)
{
  Console.WriteLine("Main starting...");

  await Task.Run(async () =>
  {
    await Job1();
  });
  await Job2();

  Console.WriteLine("Main ending...");
}

If you break out the variables so you can see the types, it will become more clear why the original code wasn't working:

static async Task Main(string[] args)
{
  Console.WriteLine("Main starting...");

  Task runTask = Task.Run(async () =>
  {
    await Job1();
  });
  Task<Task> continuationTask = runTask.ContinueWith(async t =>
  {
    await Job2();
  });

  // continuationTask is a Task<Task>.
  // This waits for the "outer" task only, not the "inner" task.
  continuationTask.Wait();

  Console.WriteLine("Main ending...");
}

Upvotes: 1

peinearydevelopment
peinearydevelopment

Reputation: 11464

To answer you question, you need to 'Unwrap' the task from the first async call as follows:

Task.Run(async () =>
         {
           await Job1();
         })
         .ContinueWith(async t =>
         {
           await Job2();
         })
         .Unwrap()
         .Wait();

Unwrap Documentation

There are a number of other things to comment on here though.

If you are using async/await, you should really use it all the way through. Your question doesn't specify which version of c# you are using. If you are using C# 7.1 or above, you should make your main method an async method as follows:

public static async Task Main()
{
  Console.WriteLine("Main starting...");
  await Job1();
  await Job2();
  Console.WriteLine("Main ending...");
}

Also, as pointed out by @Sean, Thread.Sleep is a bad idea in these scenarios, you should use await Task.Delay(1000); instead. Task.Delay Documentation

A great article with some async/await best practices can be found on MSDN as well.

Upvotes: 4

Related Questions