Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.Delay never completing

The following code will freeze forever.

public async Task DoSomethingAsync()
{
    await Task.Delay(2000);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    DoSomethingAsync().Wait();
    // Task.Delay(2000).Wait();
}

If I switch the call to DoSomethingAsync with the commented out code, it behaves as expected. I suspect that somehow the nested awaits are causing a deadlock, but I'm not sure why, or how to fix it.

like image 212
Matthew Finlay Avatar asked Jul 02 '14 07:07

Matthew Finlay


People also ask

What happens if task is not awaited?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.

What is task delay?

The Delay method is typically used to delay the operation of all or part of a task for a specified time interval. Most commonly, the time delay is introduced: At the beginning of the task, as the following example shows.

Does task delay block thread?

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

Does task delay create a new thread?

Task. Delay does not create new Thread, but still may be heavy, and no guaranties on order of execution or being precise about deadlines.


1 Answers

Assuming Button_Click runs in the GUI thread you have a deadlock on your hands.

When you use Wait on a task you are synchronously blocking the thread until the task ends, but the task will never end because the continuation (the completion of Task.Delay(2000);) must run on the GUI thread as well (which is blocked on Wait).

You have several solutions. Either use ConfigureAwait(false) to not capture the GUI thread's SynchronizationContext:

public async Task DoSomethingAsync()
{
    await Task.Delay(2000).ConfigureAwait(false);
}

Or (which I recommend) use an async void event handler (which is the only appropriate place for an async void method):

private async void Button_Click(object sender, RoutedEventArgs e)
{
    await DoSomethingAsync();
}

public async Task DoSomethingAsync()
{
    await Task.Delay(2000);
}
like image 155
i3arnon Avatar answered Oct 17 '22 04:10

i3arnon