C# Tasks.ContinueWith

Im trying to execute two different tasks from async methods but my second task only should start where the first ends. I've tryed to use ContinueWith but with no success. This is my sample code :

class Program
{
    static List<string> GlobalList1 = null;
    static List<string> GlobalList2 = null;

    static void Main(string[] args)
    {
        Task firstTask = new Task(DoFirstThing);
        firstTask.Start();
        firstTask.Wait();

        Task secondTask = firstTask.ContinueWith(o => DoSecondThing(), TaskContinuationOptions.ExecuteSynchronously);
        secondTask.Wait();

        Console.ReadKey();
    }

    public async static void DoFirstThing()
    {
        Console.WriteLine("Doing first...");

        Task t = new Task(FirstThing);
        t.Start();

        await t;
    }

    public async static void DoSecondThing()
    {
        Console.WriteLine("Doing second...");

        Task t = new Task(SecondThing);
        t.Start();


        await t;
    }

    private async static void FirstThing()
    {
        Console.WriteLine("In First..");

        Task t = new Task(() =>
        {
            List<string> list = new List<string>();

            for (int i = 0; i < 1000; i++)
            {
                list.Add(string.Format("Testing:{0}", i));
            }

            System.Threading.Thread.Sleep(2000);

            GlobalList1 = list;
        });

        t.Start();

        await t;
    }

    private async static void SecondThing()
    {
        Console.WriteLine("In Second...");

        Task t = new Task(() =>
        {
            GlobalList2 = new List<string>();
            for (int i = 0; i < GlobalList1.Count; i++)
            {
                GlobalList2.Add(GlobalList1[i].ToString() + " - testing");
            }
        });

        t.Start();
        await t;
    }
}

You may notice by the console output that tasks keep running at same time. Is it possible to change this behaviour ?

Jon Skeet
people
quotationmark

my second task only should start where the first ends

Then you should genuinely wait for it to finish. Currently, you're not doing so. You're waiting for the DoFirstThing method to return, but it will do so before it finishes awaiting t.

If instead of constructing a new Task and then calling Start(), you call Task.Run and provide a Func<T>, you can wait for the proxy task to complete:

static void Main(string[] args)
{
    Task firstTask = Task.Run(DoFirstThing);
    firstTask.Wait();
    ...
}

public async static Task DoFirstThing()
{
    Console.WriteLine("Doing first...");

    Task t = Task.Run(FirstThing);

    await t;
}

private async static Task FirstThing() { ... }

Now the Wait() call will not complete until the FirstThing() asynchronous operation has genuinely completed.

Basically, avoid async void methods in almost all cases.

That said:

  • Explicitly starting tasks rather than just calling the asynchronous method isn't usually a good idea.
  • Explicitly calling Wait() rather than awaiting a task is also rarely a good idea, as it can deadlock if the given task has a continuation that has to run on the same thread.

people

See more on this question at Stackoverflow