I would say the following two code snippets I have are equivalent, but they aren't.
The following is working correctly:
var entry3 = Task.Run(async () => await entry2.GetMemberGroupsAsync(false)).WaitForResult().FirstOrDefault();
The following code, where I just moved the Task.Run.WaitForResult
chain into an extension method, isn't working, but produces a deadlock:
var entry3 = entry2.GetMemberGroupsAsync(false).RunSynchronouslyAndReturnResult().FirstOrDefault();
public static T RunSynchronouslyAndReturnResult<T>(this Task<T> task)
{
return Task.Run(async () => await task).WaitForResult();
}
Why aren't these two code snippets equivalent?
For completeness's sake, the GetMemberGroupsAsync
method is provided by Microsoft Azure Graph API, and the function WaitForResult is defined below. As far as I can see, it doesn't do anything different depending on the caller name or sth. like that:
public static TResult WaitForResult<TResult>(this Task<TResult> task,
bool continueOnCapturedContext = false)
{
if (task == null)
{
throw new ArgumentNullException("task");
}
try
{
return PreventForDeadLocks(task, continueOnCapturedContext).Result;
}
catch (AggregateException ex)
{
if (ex.InnerExceptions.Count == 1)
{
throw ex.InnerExceptions[0];
}
throw;
}
}
public static async Task<TResult> PreventForDeadLocks<TResult>(this Task<TResult> task,
bool continueOnCapturedContext = false)
{
return await task.ConfigureAwait(continueOnCapturedContext: continueOnCapturedContext);
}
The difference here is in which synchronization context your task started. Here:
var entry3 = Task.Run(async () => await entry2.GetMemberGroupsAsync(false)).WaitForResult().FirstOrDefault();
you start your async task (I mean await entry2.GetMemberGroupsAsync(false)
) inside Task.Run
call, so UI synchronization context is not captured. But here:
var entry3 = entry2.GetMemberGroupsAsync(false).RunSynchronouslyAndReturnResult().FirstOrDefault();
You implicitly start your task (entry2.GetMemberGroupsAsync(false)
returns Task) on UI context, so UI synchronization context is captured, and you have your deadlock.
In the first case, GetMemberGroupsAsync is called on a different thread than WaitForResult.
In the second case, it is called on the same thread as WaitForResult. You're just awaiting on a different thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With