Reputation: 2937
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
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