This article explains possible causes of deadlocks in the UI of applications that use async-await, and also discusses ways to prevent this from happening.

Introduction

With the new features of the C # programming language 'related to asynchronous programming, it is possible to write sequential code snippets that will be executed asynchronously.

When a piece of code waits for a  Task  complete, its execution will remain "semantically blocked" until the  Task completes.

"Semantically blocked" means that the execution flow of the calling method will be interrupted and resumed when the asynchronous operation has been completed. This usually means that the thread will be blocked. However, in   UI threads (such as the Windows Phone UI) that require the message pump to continue working to maintain the usage experience with a good response, the execution flow is returned to the Message, and when the asynchronous operation is finished a message will be sent to the messaging system and execution will resume in the next instruction.

The test app

The test app is composed only of a text block, a progress bar (to show activity when the "work" is done in the rear) and two buttons (one that will paralyze the UI and another that does not).

How to (not) deadlock your UI using async-await screenshot.png
<PhoneApplicationPage x: Class = "PhoneApp.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns: x = "http://schemas.microsoft.com/winfx" / 2006 / xaml " xmlns: phone = " clr-namespace: Microsoft.Phone.Controls; assembly = Microsoft.Phone " xmlns: shell = " clr-namespace: Microsoft.Phone.Shell; assembly = Microsoft.Phone " xmlns: d = "Http://schemas.microsoft.com/expression/blend/2008" xmlns: mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc: Ignorable = "d"FontFamily ="StaticResource PhoneFontFamilyNormal}" FontSize = "{StaticResource PhoneFontSizeNormal}" Foreground = "{StaticResource PhoneForegroundBrush}" SupportedOrientations = "Portrait" Orientation = "Portrait" shell: SystemTray.IsVisible = "True" > <Grid x: Name = "LayoutRoot " Background = " Transparent " > <Grid.RowDefinitions > <RowDefinition Height = " Auto " /> <RowDefinition Height = "*" />

</Grid.RowDefinitions >

<StackPanel x: Name = "TitlePanel" Grid.Row = "0" Margin = "12,17,0,28" >

<TextBlock Text = "ASYNC-AWAIT BLOCKING" Style = "{StaticResource PhoneTextNormalStyle } " />

<TextBlock x: Name = " TextBlock1 " TextWrapping = " Wrap " VerticalAlignment = " Top " Style = " {StaticResource PhoneTextTitle1Style} " Text = " 00:00:00 "/>
<ProgressBar x: Name ="ProgressBar1" Height = "10" IsIndeterminate = "True" Visibility = "Collapsed" />
</ StackPanel >

<StackPanel x: Name = "ContentPanel" Grid.Row = "1" Margin = "12,0,12,0 " >

<Button x: Name = " Button1 " Content = " paralyze " Click = " Button1_Click " />
<Button x: Name = " Button2 " Content = "do not stop" Click ="Button2_Click" />

</ StackPanel >
</ Grid >
</ phone: PhoneApplicationPage >

The test method

For the purposes of this article, our asynchronous method that does "work" in the back will only return the date / time after a five-second delay:

Private async Task < DateTime > GetValueAsync ( )
{
     await Task . Delay ( 5000 ) ;
    Return DateTime . Now ;
}

Stopping the UI

When calling such a method from the UI we might be tempted to, instead of waiting for the  Task  complete, to directly access the Result property  :

Private  void Butto1_Click ( object sender, RoutedEventArgs e )
{
    // ...
    var datetime = GetValueAsync ( ) . Result ;
 
    This . TextBlock1 . Text  = datetime . ToLongTimeString ( ) ;
    // ...
}

This will paralyze the UI because the   messaging thread will be blocked and the continuation that will be placed there will never be staggered to execute, thus paralyzing the UI.

Not paralyzing the UI

The simplest way to not paralyze the UI is to wait for the   returned Task to complete instead of directly accessing the Result property  :

Private async void Button2_Click ( object sender, RoutedEventArgs e )
 
{
  // ...
   var datetime = await GetValueAsync ( ) ;
   TextBlock1 . Text  = datetime . ToLongTimeString ( ) ;
    // ...
}

In this way, the UI will continue to handle messaging messages and the continuation will be escalated to execution when the task finishes.

Conclusion

When deciding to use  Task s in the UI one should always use  async - await  because the C # compiler (and the Visual Basic compiler) will generate a state machine that will then escalate to execute in the correct context without stopping the UI.

Sample Projects

Download a solution with sample projects for Windows Phone 7.5 and Windows Phone 8 from here: File: How to (not) deadlock your UI using async-await sample solution.zip

Resources

Originally was contributed on 30 July 2013 by paulo.morgado