Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to await until Task.ContinueWith inner task finishes

Take a look at this code:

    private async Task InnerTask(bool outerTaskResult)
    {
        Console.WriteLine("2");
        await Task.Factory.StartNew(() => Thread.Sleep(10000));
        Console.WriteLine("3");
    }

    private async void Button2_Click(object sender, RoutedEventArgs e)
    {
        var task = Task.FromResult(false);
        Task<Task> aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result));
        Console.WriteLine("1");
        await aggregatedTask;
        Console.WriteLine("4");
    }

The desired output is:

1
2
3
4

But I get:

1
2
4
3

This probably has something to do with InnerTask being executed on a different thread.

I'm using ContinueWith because the tasks in the original code are dynamically created and queued this way.

Using .Wait() method (see below) works, but I think it's a bad idea, as the method is blocking.

task.ContinueWith(task1 => InnerTask(task1.Result).Wait())

What's the correct approach here?

like image 852
Andrzej Gis Avatar asked Feb 18 '15 15:02

Andrzej Gis


People also ask

How do I wait until task is finished in C#?

The Task. WaitAll() method in C# is used to wait for the completion of all the objects of the Task class. The Task class represents an asynchronous task in C#. We can start threads with the Task class and wait for the threads to finish with the Task.

Can you await a task twice?

await hides all this complexity from you, and it allows you to await the same task in ten different places (very useful for e.g. asynchronous lazy initialization). can I be assured that the method pointed by task wont be executed twice even if the task is running or ran already ? @BilalFazlani Yes, you can.

What is a continuation task?

A continuation task (also known just as a continuation) is an asynchronous task that's invoked by another task, known as the antecedent, when the antecedent finishes.

Does await task delay block thread?

await Task. Delay(1000) doesn't block the thread, unlike Task. Delay(1000).


1 Answers

You can use TaskExtensions.Unwrap() (which is an extension method on Task<Task>) to unwrap the outter task and retrieve the inner one:

private async void Button2_Click(object sender, RoutedEventArgs e)
{
    var task = Task.FromResult(false);
    Task aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result)).Unwrap();
    Console.WriteLine("1");
    await aggregatedTask;
    Console.WriteLine("4");
}

Note that to simplify this entire thing, instead of ContinueWith style continuation you can await on your tasks:

private async void Button2_Click(object sender, RoutedEventArgs e)
{
    var task = Task.FromResult(false);

    Console.WriteLine("1");

    var result = await task;
    await InnerTask(result);

    Console.WriteLine("4");
}
like image 199
Yuval Itzchakov Avatar answered Oct 04 '22 20:10

Yuval Itzchakov