OSH
OSH

Reputation: 2937

Task async/await not working from WPF as it works in other scenarios

I ran into a very odd behavior. After a lot of digging I was able to find a scenario that shows that (apparently) using task await directly from a WFP application doesn't work as expected. However, creating a task and doing the await within it works ok.

I used the following steps to illustrate (using VS 2013). In a new WPF application use this main.xaml.cs:

using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        static async Task<bool> Test_int()
        {
            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

            Thread t = new Thread(() =>
            {
                Thread.Sleep(1000);
                tcs.SetResult(true);
                //Console.WriteLine("TCS set");
            });
            t.Start();

            //int i = tcs.Task.Result;   //<-- this always works, but doesn't take    advantage of await semantics
            var ret = await tcs.Task;

            return ret;
        }

        static void Test()
        {
            var tt = Test_int();
            //(1)
            tt.Wait();
            //Console.WriteLine("Test done");
        }

        public MainWindow()
        {
            InitializeComponent();

            //option 1 -- works
            Task t = new Task(Test);
            t.Start();
            t.Wait();

            //option 2 -- hangs indefinitely
            Test();
        }
    }
}

The behavior I see is that running the method Test() directly causes the application to hang (in the await line marked with (1)), while running it inside a task runs correctly and finish.

I solved my original problem by running in the context of a task, but I would like to understand the cause of the problem. BTW the same Test() method does work directly when running in a console application.

Why doesn't await work (the same way) when running directly from a WPF application?

Upvotes: 2

Views: 2852

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456322

You're running into a classic deadlock scenario that I describe on my blog. In summary, await by default will capture a "context" and use that to resume the async method. In this case, it's a UI context, and if you block the UI thread (by calling Wait), then the async method cannot resume and never completes.

The proper solution is to use await instead of Wait.

Furthermore, you shouldn't use the Task constructor, Start, or Thread (use Task.Run instead, but only if you need to execute code on a background thread).

I recommend you read my async intro blog post and then my async best practices MSDN article. They should help you out.

Upvotes: 9

Related Questions