TheHvidsten
TheHvidsten

Reputation: 4428

Async task deadlocks if task is extracted first

I'm using Microsoft's AsyncHelper (source) to call an async method from a synchronous context. This works just fine:

Result r = AsyncHelper.RunSync(async () => await SomeClass.SomeMethodAsync());

However, if I extract the Task and then try to run this extracted task synchronously instead, I encounter a deadlock.:

Task<Result> t = SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(async () => await t);

Why does this happen, and what can be done to make this run?

Upvotes: 1

Views: 310

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456417

AsyncHelper.RunSync uses the thread pool hack to ensure that its delegate is called without a context, thus making it safe to block on (assuming that the delegate is safe to be called on a thread pool thread). In your code, SomeMethodAsync is executed on a thread pool thread, so any awaits will not capture a context.

what can be done to make this run?

Well, you would use the first code sample instead of the second.

If you want to have a construct that represents some code to run, then you should use a delegate type such as Func<Task<T>>. E.g.:

Func<Task<Result>> func = () => SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(func);

With asynchronous code, Task<T> does not represent some code to run; it represents some code that has already started. Use Func<Task<T>> to represent some code to run.

Upvotes: 3

Related Questions