Bug 27528 - Wait()-ing for a Task that is waiting for a Task hangs forever (await works)
Summary: Wait()-ing for a Task that is waiting for a Task hangs forever (await works)
Status: RESOLVED ANSWERED
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 5.1
Hardware: PC Windows
: --- blocker
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2015-02-28 10:33 UTC by Matthew Leibowitz
Modified: 2015-03-02 17:09 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
A reporo (10.29 KB, application/x-zip-compressed)
2015-02-28 10:33 UTC, Matthew Leibowitz
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description Matthew Leibowitz 2015-02-28 10:33:55 UTC
Created attachment 10100 [details]
A reporo

When calling await on a Task, it never returns. The await keyword does:

    await TaskAsync(runAsync); // works
    TaskAsync(runWait).Wait(); // hangs

The code:
  
    private async Task TaskAsync(Button button) {
        var result = await TaskAsyncInternal();
    }

    private Task<bool> TaskAsyncInternal() {
        // tasky stuff
    }

NOTE: there is no problem if I call Wait() or await TaskAsyncInternal directly.

I have attached a repro case that fails for me every time.

Devices: Nexus 5 (4.4.4) and my Nexus 7 (5.0.2)
IDE: Visual Studio 2013 Pro Update 3
Plugins: Xamarin 3.9.302.0 (80f4e84)
         Xamarin.Android 4.20.0.34 (49a04b966feb40dfdba49d57ba16249b66d606a6)
         Xamarin.iOS 8.6.1.0 (3b3ef438017c7ecf486defa9e01567a5f2b3cb2a)
         Xamarin.iOS Unified Migration 1.0
Comment 1 Jonathan Pryor 2015-02-28 10:57:34 UTC
The sample is buggy/broken because it deadlocks.

Your Click event handlers run on the UI thread, as you'd expect, which is why TaskAsync() works the way you want it to:

1. Click 'Run with async/await', and
1.a: the button text changes to 'Running...',
1.b: then after 2 seconds
1.c: the button text changes to 'Complete: True'.

Updating the button while having the app be responsive requires that the UI thread run. Specifically, it means that the Click event handler must *return* so that the UI can be updated.

Such is the beauty of async/await: the method actually returns, even though source-code-wise it doesn't look like it returns; the compiler is instead emitting something like:

    private Task TaskAsync(Button button) {
         button.Text = "running...";
        Task t = ...;
        return t.ContinueWith (_ => TaskAsyncInternal().Wait())
            .ContinueWith (_ => button.Text = "complete: " + result);
    }

...or something vaguely like that. Note that it *returns* a Task without actually executing all the statements!

Which brings us to runWait, which performs a Wait() in the Click event handler. The Wait() requires that the Task complete fully *before* the Click event will return to the UI thread, and since the async/await machinery is working by "queueing" future actions on the UI thread...the UI thread currently *blocked* on a Wait()!...you now have deadlock, and the app doesn't respond.

Do Not Call Wait() from the UI thread.
Comment 2 Jeremy Kolb 2015-03-02 17:09:20 UTC
This would be more easily debugged if https://bugzilla.xamarin.com/show_bug.cgi?id=12606 were fixed