Reputation: 3573
First, sorry for yet another "why my async action hangs" question but I believe this question is different enough.
Surveying dozens of similar questions, the problem of async action deadlock is either in locking yourself out (.Result
), using limited resources or using library components incorrectly (web requests seems popular). In the following example, I cannot find any from above:
private async Task ExecuteAsync(Task<int> task)
{
// entering on current thread, that is the main UI thread
await task // execute "task" asynchronnously (on a different thread)
.ConfigureAwait(false); // when done, no need to return to main thread
MessageBox.Show("success"); // succes indicator
}
public MainWindow() //wpf window ctor
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var task = new Task<int>(() => 42); // make an Action wrapping sychronnous method
// fire and forget, never caring for .Result, disard even the task
var _ = ExecuteAsync(task).ConfigureAwait(false);
}
I have commented the sample with my best try on exaplaining how things (should) work, but something in my explanation must be wrong. Even though MainWindow
ctor does not deadlock, the Action () => 42
is never executed and "success" message is not shown. After some debugging I managed to fix the sample (using Task.FromResult
), but I am still not sure what is wrong with it as it is now and even more importantly why.
What is the error in my reasoning and why was the action never executed/finished?
Upvotes: 0
Views: 100
Reputation: 43876
You did not start the task! You only declared it. Simply await
ing it does not "fire" it.
private async Task ExecuteAsync(Task<int> task)
{
// at first do start the task
task.Start();
await task.ConfigureAwait(false);
MessageBox.Show("success");
}
Note that ConfigureAwait(false)
does not guarantee that execution will be continued on a different thread. It only says that you don't need it to be resumed on the original thread. And resuming UI work (like MessageBox.Show()
) on a non-UI thread is not recommended.
As NineBerry pointed out, if you want to wrap a synchronous method and let it run on a different thread, you should use Task.Run()
:
var task = Task.Run(() => YourSynchronousCall());
Upvotes: 5