1

I have the following methods:

public override bool SyncNavigationMethod()
{
    AsyncShowDialog().Wait();
    return true;
}

public Task AsyncShowDialog()
{
    //code to show dialog and process user input from the dialog.
}

what happens is that the app goes into a deadlock when SyncNavigationMethod is called.

My guess is that it runs on the MainThread, who is waiting for AsyncShowDialog to complete, and the dialog that is shown cannot call it's callback because it's the MainThread that calls it. And so, the main thread waits to itself and it's a deadlock.

More information:

  • runtime - UWP.
  • device: phone (as described above) desktop (the app freezes before the dialog is shown).
  • I have tried to use .Wait() \ .Result on AsyncShowDialog.
  • I have tried to use a ManualResetEvent after calling the AsyncShowDialog to block the code from progressing while AsyncShowDialog is running.

Am I right suspecting a deadLock?

How can I call AsyncShowDialog from SyncNavigationMethod without this deadlock?

Thanks.

Mr. Mantis
  • 21
  • 4

1 Answers1

2

I will start with one of the best blog post by Stephen Cleary, which explains, how the synchronous blocking of an asynchronous call leads to deadlock and that's true for all systems except Console, which doesn't have a UI context thread:

Now regarding your code and points:

And so, the main thread waits to itself and it's a deadlock.

Yes it does, you have correctly understood it's a deadlock, due to Mainthread blocking itself

Wait, Result and ManualResetEvent, they all synchronously block the Async code, thus the same result

Possible solution:

If the call is a Rest API or a web based call, then make the everything Async and IIS will ensure that it can return post top level Async-Await execution, something like:

public async override Task<bool> SyncNavigationMethod()
{
    await AsyncShowDialog();
    return true;
}

public async Task AsyncShowDialog()
{
    await SomeOperation();
}

Return value of Task<bool> would be automatically unwrapped

Other option:

If you cannot make the SyncNavigationMethod() Async, then try this:

public override bool SyncNavigationMethod()
    {
        List<Task> taskList = new List<Task>();
        taskList.Add(AsyncShowDialog());
        Task.WhenAll(taskList.ToArray());
        return true;
    }

    public async Task AsyncShowDialog()
    {
        await SomeOperation();
    }
Mrinal Kamboj
  • 11,300
  • 5
  • 40
  • 74
  • 1
    `Task.WhenAll(....)` return a task that waits for all the tasks it receives. So, I will have to wait that task as well. By doing that I just wrapped the `AsyncShowDialog()` with another task and it doesn't help. still that you for your time. I changed the infra-structure yesterday to support `public async override Task SyncNavigationMethod()` as your first suggestion and what I was trying to avoid. – Mr. Mantis Aug 25 '16 at 12:15
  • Can you also try `ConfigureAwait(false).GetAwaiter().GetResult()`, but then `ConfigureAwait`, need to be used all the way up to the top most call. You needn't make top method `Async` – Mrinal Kamboj Aug 25 '16 at 12:23