Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asyc method using await Task.Run() never "completes"

I have a method that is defined as

public async Task SomeAsyncMethod()
{
   DoSomeStuff();
   await Task.Run(() => {
     DoSomeSyncStuff();
     DoSomeOtherSyncStuff();
   });
   var someDebugVariable = "someDebugValue";
}

The method itself does exactly what it is supposed to do and everything runs fine. Yet ... it looks like the "outer" async Task never completes.

Example: When I call it like this

public void CallerMethod()
{
   Task t = SomeAsyncMethod();
   t.Wait();
}

the t.Wait() never completes. Furthermore: if I place a breakpoint at the assignment of someDebugVariable it never gets hit.

I might add that DoSomeSyncStuff and DoSomeOtherSyncStuff really do what they are supposed to and debugging through them tells me that they both complete.

To prove my point I modified my method like this, and the results are still the same.

public async Task SomeAsyncMethod()
{
   DoSomeStuff();
   await Task.Run(() => {
     /*
     DoSomeSyncStuff();
     DoSomeOtherSyncStuff();
     */
     var a = 2; var b = 3; var c = a + b;
   });
   var someDebugVariable = "someDebugValue";
}

EDIT

I have tried removing everything but the await Task.Run and it does not change anything. It still does not complete.

The application is a WPF application. The caller thread is the UI thread.

What am I missing here?

like image 921
Hemisphera Avatar asked Jan 25 '16 14:01

Hemisphera


1 Answers

The t.Wait() call is causing a deadlock, and also makes the async call entirely pointless. I believe if you change the code to

await Task.Run(() => {
// ...
}).ConfigureAwait(false);

You can fix the deadlock and let the code proceed, but you should really get rid of the t.Wait() call. Anything that needs to be done with the results of the sync function calls should be done after the awaited task, not after the call of the async function.

More in depth: task.Wait() will block all execution on the main thread while the task is running. When the await task completes, it tries to marshall back to the main thread, but the main thread is blocked! Since A is waiting for B, and B is waiting for A, you get a deadlock.

See: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

like image 92
Steve Avatar answered Sep 29 '22 17:09

Steve