Search code examples
c#asynchronousasync-awaitsynchronizationcontext

Why does blocking on async in a Windows Service cause a deadlock?


I have an issue with deadlock in my code.

My code looks like this:

public async Task DoStuff(input)
{
    await AsyncMethod();
    //internally calls an async method, and blocks for its return. sometimes couses deadlocks. 
    new MyService().DoMoreStuff();
}

MyService.DoMoreStuff implementation :

DoMoreStuff()
{
    return DoSuffAsyncMethod().Result;
}

This code sometimes gives me deadlock on DoSuffAsyncMethod,

inside MyService.DoMoreStuff method.

If, however, I wrap the offending code in a task, dead locks no longer occur

public async Task DoStuff(input)
{
    await AsyncMethod();
    await Task.Run(new MyService().DoMoreStuff());
}

More Info

This code runs in the context of a windows service Thus , no synchronization context is involved.

I know how to solve the issue , yet still do not understand why the code would deadlock .

Can anyone suggest an explanation to the deadlocks of mixed sync async code , without synchronization context ?

EDIT

Thanks for the comments.

I am assuming it dead-locking.

Actual scenario is a little more complex , so I simplified it a little.

In DoSuffAsyncMethod() we are calling a remote async service , after some predefined time elapsed - we are timing out.

Analyzing the request and receiving service, revealed that messages are actually transmitted correctly .

So, barring network or network framework related issues , we are left with deadlock.

We assume it is deadlock , since once we restructured the code , the timeouts in DoSuffAsyncMethod went away.

Edit 2 The code

DoSuffAsyncMethod().Wait().Result

is wrong.

Correct code is

DoSuffAsyncMethod().Result

Issue was due to ConfigureAwait(true) being called deeper down the call stack .

Thanks for the help.


Solution

  • await basically means: "Hey thread go on doing your stuff, when I'm ready I'll ask for you to continue my job". The thread is like: "Yes, but I'll come to you when I've completed the rest of my work". Then you ask the thread to Wait the previous task, but it'll never complete the work because to complete it needs the thread to come back to him (yes, the thread that is Waiting for it...)

    But when you do

    await Task.Run(new MyService().DoMoreStuff());
    

    The thread after await is available to resume the task that previously awaited (DoMoreStuff()), so they are both able to complete their work.

    More info, and probably better explaination can be found here