I’ve discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.
Yes, I have a blog post documenting this (AFAIK it’s not documented on MSDN). The deadlock happens because of two things:
- There’s a mixture of
async
and blocking code (i.e., anasync
method is callingWait
). - Task continuations are scheduled using
TaskContinuationOptions.ExecuteSynchronously
.
I recommend starting with the simplest possible solution: removing the first thing (1). I.e., don’t mix async
and Wait
calls:
await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();
Instead, use await
consistently:
await SendAwaitResponse("first message");
await SendAwaitResponse("second message");
If you need to, you can Wait
at an alternative point further up the call stack (not in an async
method).
That’s my most-recommended solution. However, if you want to try removing the second thing (2), you can do a couple of tricks: either wrap the SetResult
in a Task.Run
to force it onto a separate thread (my AsyncEx library has *WithBackgroundContinuations
extension methods that do exactly this), or give your thread an actual context (such as my AsyncContext
type) and specify ConfigureAwait(false)
, which will cause the continuation to ignore the ExecuteSynchronously
flag.
But those solutions are much more complex than just separating the async
and blocking code.
As a side note, take a look at TPL Dataflow; it sounds like you may find it useful.