Writing multithreaded programs using Async & Await in C#


The biggest feature in C# and Visual Basic languages in Visual Studio 11 is inclusion of first class language support for asynchrony. Writing multi-threaded programs that scale, are easily modifiable, maintainable and understandable by more than one person (i.e. the one that wrote the code) is hard. This is certainly something I have seen people get wrong time and time again.

Probably the most dangerous word to use with undergraduate or even postgraduates is the word “Thread”. When developing software systems, this is certainly an area that requires somebody experienced, and proactive enough to ensure that developers are monitored when they are assigned tasks using threading, as things can get out of hand very quickly.. I have always tried to ensure that developers refrain from using the Thread class and suggesting they use the ThreadPool  and its QueueUserWorkItem  method or the background worker component where possible, but there are times when you have to implement the IAsyncResult design pattern, which makes understanding what your normally synchronous application (and mind-set) hard, because there is an Inversion of Control in the code that is executing, requiring you use a WaitCallBack and WaitHandles and ManualResetEvent and AutoResetEvent classes.

As we move forward, it is more important that developers are as productive as possible, especially in a world where devices are proliferating at the rate that they are. I can now program a Computer, Mobile Phone or Tablet, where connectivity, and updating is a real issue on tablets and phones, so being able to write robust, multi-threaded code quickly and relatively bug free increases in importance.

Note that I am using WPF in this example, if you would like to know how to do this in WinRT/Metro, then have a look at this example.

Single Threaded Example

If you run Visual Studio and create a new WPF application and call the project AsyncWpfApplication

NewProject

This synchronous application application is going to process a list of URLs, and calculate the size of the pages so please ensure you add a reference to System.Net.Http

SystemNet

Add the following XAML markup

<Window x:Class="AsyncWpfApplication.MainWindow"
Title="MainWindow" Height="400" Width="600">
<Grid>
 
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
 
<TextBox Margin="20" Grid.Row="0" HorizontalAlignment="Left" TextWrapping="Wrap" FontFamily="Lucida Console" x:Name="resultsTextBox" Height="250" Width="500" />
<Button Grid.Row="1" HorizontalAlignment="Right" Margin="0,0,70,20" Content="Start" x:Name="startButton" Height="22" Width="75" Click="startButton_Click_1" />
 
</Grid>
</Window>
 

Add the following in the code behind

using System;
using System.Collections.Generic;
using System.Windows;
using System.Net.Http;
using System.Net;
using System.IO;
using System.Threading.Tasks;
 
namespace AsyncWpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
 
private void startButton_Click_1(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear();
SumPageSizes();
resultsTextBox.Text += "\r\nControl returned to startButton_Click.";
}
 
private void SumPageSizes()
{
// Make a list of web addresses.
IEnumerable<string> urlList = SetUpURLList();
 
var total = 0;
foreach (var url in urlList)
{
// GetURLContents returns the contents of url as a byte array.
byte[] urlContents = GetURLContents(url);
 
DisplayResults(url, urlContents);
 
// Update the total.
total += urlContents.Length;
}
 
// Display the total count for all of the web addresses.
resultsTextBox.Text += string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
}
 
 
private IEnumerable<string> SetUpURLList()
{
var urls = new List<string>
{
};
return urls;
}
 
 
private byte[] GetURLContents(string url)
{
// The downloaded resource ends up in the variable named content.
var content = new MemoryStream();
 
// Initialize an HttpWebRequest for the current URL.
var webReq = (HttpWebRequest)WebRequest.Create(url);
 
// Send the request to the Internet resource and wait for
// the response.
using (var response = webReq.GetResponse())
{
// Get the data stream that is associated with the specified URL.
using (Stream responseStream = response.GetResponseStream())
{
// Read the bytes in responseStream and copy them to content. 
responseStream.CopyTo(content);
}
}
 
// Return the result as a byte array.
return content.ToArray();
}
 
private void DisplayResults(string url, byte[] content)
{
// Display the length of each website. The string format
// is designed to be used with a monospaced font, such as
// Lucida Console or Global Monospace.
var bytes = content.Length;
// Strip off the "http://&quot;.
var displayURL = url.Replace("http://&quot;, "");
resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
}
}
}
 

If you then hit F5 to run the application and press start you will find that the start button sticks and the application itself is unresponsive because of all the work that is blocking the main UI thread. After a few moment you should get the following

Screen

Multithreaded Example

When retrofitting the new asyc language features you need to be aware of the following

  1. The new asyc language capabilities are based around Task<T> found in System.Threading.Tasks.Task<TResult>. Knowing how that class works with increase the ease of you ability to use the new asyc features
  2. Any method that uses the new asynchronous functionality must use the new keyword asyc.
  3. There are a plethora of new classes in the .NET framework that are suffixed with Asyc that return a Task<T> that you can use with the new await keyword.
using System;
using System.Collections.Generic;
using System.Windows;
using System.Net.Http;
using System.Net;
using System.IO;
using System.Threading.Tasks;
 
namespace AsyncWpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
 
private async void startButton_Click_1(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear();
await SumPageSizesAsync();
resultsTextBox.Text += "\r\nControl returned to startButton_Click.";
}
 
private async Task SumPageSizesAsync()
{
// Make a list of web addresses.
IEnumerable<string> urlList = SetUpURLList();
 
var total = 0;
 
foreach (var url in urlList)
{
// GetURLContentsAsync returns a Task<T>. At completion, the task
// produces a byte array.
Task<byte[]> getContentsTask = GetURLContentsAsync(url);
byte[] urlContents = await getContentsTask;
 
// The following line can replace the previous two assignment statements.
//byte[] urlContents = await GetURLContentsAsync(url);
 
DisplayResults(url, urlContents);
 
// Update the total.         
total += urlContents.Length;
}
 
// Display the total count for all of the websites.
resultsTextBox.Text +=
string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
}
 
 
 
 
private IEnumerable<string> SetUpURLList()
{
var urls = new List<string>
{
};
return urls;
}
 
private async Task<byte[]> GetURLContentsAsync(string url)
{
// The downloaded resource ends up in the variable named content.
var content = new MemoryStream();
 
// Initialize an HttpWebRequest for the current URL.
var webReq = (HttpWebRequest)WebRequest.Create(url);
 
// Send the request to the Internet resource and wait for
// the response.
Task<WebResponse> responseTask = webReq.GetResponseAsync();
using (WebResponse response = await responseTask)
{
// The following line can replace the previous two lines.
//using (WebResponse response = await webReq.GetResponseAsync())
 
// Get the data stream that is associated with the specified url.
using (Stream responseStream = response.GetResponseStream())
{
// Read the bytes in responseStream and copy them to content.
// CopyToAsync returns a Task, not a Task<T>.
Task copyTask = responseStream.CopyToAsync(content);
 
// When copyTask is completed, content contains a copy of
// responseStream.
await copyTask;
 
// The following line can replace the previous two statements.
//await responseStream.CopyToAsync(content);
}
}
 
// Return the result as a byte array.
return content.ToArray();
}
 
 
 
private void DisplayResults(string url, byte[] content)
{
// Display the length of each website. The string format
// is designed to be used with a monospaced font, such as
// Lucida Console or Global Monospace.
var bytes = content.Length;
// Strip off the "http://&quot;.
var displayURL = url.Replace("http://&quot;, "");
resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
}
}
}

    If you examine the retrofitted example above you will see that the synchronous methods have indeed been replaced with their methods that are suffixed with Async e.g. SomeMethodAsyc and all you have to do is use the await keyword until the asynchronous task completes. The C# language team have really made asynchronous programming “easy peasy lemon squeezy”.

Introduction to Windows 8 Metro & WinRT (part 2)


Welcome to the second in this two part series on developing Metro applications in Windows 8. The first part is available here

Introduction to Windows 8 Metro & WinRT (part 1)

In the first part you saw how to create a Metro/WinRT application using the Blank Application Template. In this part you see how to utilise both the Grid and Split application templates

Grid Application

If you open Visual Studio (or the Visual Basic or C# Express editions) and select the Grid Application Template and call the project GridApplication (take note of the information on the right in the New Project Dialogue that explains the core features of this template). This template (in a nutshell) allows you to create Master/Detail views of your data in a touch friendly way.

New Project

After clicking OK, it is best that you hit F5 and ensure you build the project as there are custom resources that need to be built, if you fail to do this then the XAML designer will show errors.

Note:  I am also experiencing a bug where the project is blank in the solutions explorer, if you run into this issue, close the application in Visual Studio, and restart it, and it should show up now. I have also (this morning) been offered some updates for Visual Studio that I hope resolve some of these issues in Visual Studio, I recommend you update

Updates

If you look at your solution explorer you will find that there are some additional folders and files. Take special note of the DataModel folder, and the three pages highlighted below

Solution Explorer

If you (like me) have been using MVVM religiously in your WPF, Silverlight or Windows Phone applications, a lot of the structure of the application should be familiar. If you go into GroupedItemsPage.xaml you will find the following XAML where the SampleDataSource is bound. Also note that there are two main Views in the XAML. When viewing data normally the GridView is used (wrapped in a scroll viewer) but when you pin the application to the side of your screen, the ListView is used instead.

<UserControl.Resources>
 
<!– Collection of items displayed by this page –>
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"
d:Source="{Binding ItemGroups[0].Items, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
</UserControl.Resources>
 

Look at the code behind of the App.xaml file, here you will see how the data gets populated and fed to the windows that will display the data by creating an instance of  the SampleDataSource and passing the ItemGroups into the constructor of the page.

/// <summary>
/// Invoked when the application is launched normally by the end user.  Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
// TODO: Create a data model appropriate for your problem domain to replace the sample data
var sampleData = new SampleDataSource();
 
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
 
// Create a Frame to act navigation context and navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
var rootFrame = new Frame();
rootFrame.Navigate(typeof(GroupedItemsPage), sampleData.ItemGroups);
 
// Place the frame in the current Window and ensure that it is active
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
 

If you run the application you will find you have this master page

Master.

If you select any items in the list you will be taken to this details view

Detail

If you select the group title (look at the arrows in the master page image) you will have this view

Title

Also take note of the touch friendly handles

Handles

If you move your mouse to the top of the screen so a little hand cursor show, and then drag the app to the right hand corner, you can pin the application to the side (this is the aforementioned ListView). Dragging the Grid Splitter to the left will restore full screen mode

Snap

In your Visual Studio Solution, if you navigate to your DataModel folder, you will find the SampleDataSource.cs. This (as you might have guessed) contains the data that you see in the application in the following four classes (as a best practice you will want to move these classes into their own files)

Data

The Simulator

A really useful tool in Visual Studio is called the Simulator. This in essence, allows the ability to run the application in Simulation mode, where you can test how you app will respond to different screen resolutions for example. If you toggle the build setting to simulator and build

Simulator

you will have the following

Simulator Actual

You can rotate the application 90 degrees to see what it looks like

Rotated

If you want to see what the application looks like on a bigger screen

Bigger screen

Split Application

If you open Visual Studio (or the Visual Basic or C# Express editions) and select the Split Application Template and call the project SplitApplication (take note of the information on the right in the New Project Dialogue that explains the core features of this template).

New Project

The assets and files for the SplitApplication are almost identical to the GridApplication except here you have a SplitPage and an ItemsPage.

Split and Items

Main View

If you press F5 to build you should have the following

MainWindow

Split View

 

Items

As you can see Visual Studio makes it very easy for you to get started and create applications that look beautiful and can bind to data sources very easily. I really love the Expression Designer they have included in Visual Studio 11,  it really makes working with mark-up like XAML so much easier.

Introduction to Windows 8 Metro & WinRT (part 1)


Welcome to the first in this two part series on developing Metro application in Windows 8. Part two is available here

Introduction to Windows 8 Metro & WinRT (part 2)

In this two part series, I will demonstrate just how easy it is to create your first Windows Metro application, and highlight some of the changes that you will need to be aware of if you are coming from a WPF, Silverlight or Windows Phone background. The series will concentrate specifically on the three different types of Metro application available to you in Visual Studio.

The first part will demonstrate how to create a blank Metro application, familiarise yourself with the location of the resources and files, and finally demonstrate how to load some data from your computer using the new async and await keywords in C# 5.0.

The second part will demonstrate how to create a Grid and Split Application, highlighting the differences between the two, and also show you the amazing “Simulator” that incidentally, will please project managers no end, as they will have to purchase far less hardware to test their Metro applications on.

    The first thing to do, is ensure you download the tools. In order to create a Windows Metro application, you will need to be running Windows 8 (consumer preview available here) and Visual Studio 11 (beta available here or any of the express editions. If you are using Windows 7 and Visual Studio 11 beta, or Visual Studio Express, then the metro templates will not be available to you in Visual Studio.

Windows 8

 

Windows8

Visual Studio 11

 

Visual Studio

 

Creating a Simple Metro Application

If you run Visual Studio, select New Project and then the Windows Metro Style template (Visual Basic template is at the bottom of this screenshot), also note that there are three application types available that are highlighted in yellow. Select the Blank Application Template and name the project BlankApplication and click OK

New Project

 

The first thing to notice is that your solution explorer has an Assets folder and a Common folder

 

Blank Solution

In the Common Folder you have a StandardStyles.xaml file that (as you might guess) contains the styles all Metro applications use, and since one of the Metro Guidelines is that “a Metro Style app should look like a Metro application”, these styles are invaluable. If you also look at both the XAML and code being of the App.xaml you will see that this works like WPF or Silverlight if you have ever used the navigation framework and it also explain why when you hit F5 you get a blank page

Viewing Images from my computer

If you double click on the BlankPage.xaml and add the following mark-up and code to click a button and load some images from your computer. Also be aware that everything in WinRT is asynchronous. Since it is Olympic year, I have a folder  in “My Pictures” on my computer with some aerial photos of the Olympic Village as a work in progress

XAML

<Page
x:Class="BlankApplication.BlankPage"
xmlns:local="using:BlankApplication"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
<Button Content="Find Pictures" HorizontalAlignment="Center" Command="{Binding Path=LoadImages}" Click="Button_Click" />
<Image x:Name="image1" />
</Grid>
</Page>

Code Behind

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Popups;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace BlankApplication
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class BlankPage : Page
{
public BlankPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.  The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var dialog = new MessageDialog("Would you like to find some pictures?");
dialog.Commands.Add(new UICommand("Yes", null, "Yes"));
dialog.Commands.Add(new UICommand("No", null, "No"));
var result = await dialog.ShowAsync();
if (result.Id.ToString() == "Yes")
{
var picker = new FileOpenPicker();
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.FileTypeFilter.Add(".jpg");
var file = await picker.PickSingleFileAsync();
if (file != null)
{
IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
bitmapImage.DecodePixelHeight = 400;
bitmapImage.DecodePixelWidth = 400;
bitmapImage.SetSource(fileStream);
image1.Source = bitmapImage;
}
}
}
}
}

Run Application

If you select F5 in Visual Studio, and click on Find Pictures

Run

Find Pictures

Here you can see the text that you added to the command in the code behind

Find

View Images

Finally here you can view all the images that I have in the My Pictures folder on my computer

My Pics

As you can see there are a lot of similarities for WPF and Silverlight developers coming to WinRT, and though some libraries will differ it will not be that difficult to incorporate these differences to your existing toolset.