Giter VIP home page Giter VIP logo

crossthreadingtests's Introduction

Async/await in Desktop Applications

This repository contains a sample WinForms application to demonstrate async/await "challenges" in UI programming.

Demo App

The form contains three buttons which are intended to download the the content from http://microsoft.com asynchronously and show it in a TextBox.

Cross-Thread issue :(

private async void button1_Click(object sender, EventArgs e)
{
    // await a completed task => will continue synchronously
    await SomeFastAsyncOperation().ConfigureAwait(false);

    // await a slow task => will continue in another thread
    var t = await SomeSlowAsyncOperation().ConfigureAwait(false);

    // write text to text box
    textBox1.Text = t;
}

When clicking the first button, an InvalidOperationException will be thrown with the message

Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.

That's because in Win32 UIs you must access controls from the same thread that created them. Because the after awaiting SomeSlowAsyncOperation the method continues not in the main thread but a nackground thread, accessing textBox1 is forbidden.

When you debug button1_Click, pay attention to the Threads tool window.

Debugger

  1. Entering the method, you'll be on thread #1, the main thread.
  2. After calling SomeFastAsyncOperation, the code continues on thread #1. That's because the method returns an already completed task, so the code can continue synchronously.
  3. In contrast, SomeSlowAsyncOperation returns a not-completed task, therefore the succeeding code will continue not another one. (The UI thread will be released here and continue pumping the Win32 message queue)
  4. The property textBox1.Text will be set in said background thread and fail, because Win32 controls mist be accessed from the same thread that created them.

Blocking :(

private async void button2_Click(object sender, EventArgs e)
{
    // await a completed task => will continue synchronously
    await SomeFastAsyncOperation().ConfigureAwait(false);

    // await a slow task => will continue in another thread
    var t = SomeSlowAsyncOperation().ConfigureAwait(false).GetAwaiter().GetResult();

    // write text to text box
    textBox1.Text = t;
}

Clicking the second button will freeze the application. The GetAwaiter().GetResult() invocation will try to re-enter the the main thread, which is waiting for the task, so we'll run into a dead-lock.

Run smoothly :)

private async void button3_Click(object sender, EventArgs e)
{
    // force switch to threadpool thread
    await TaskScheduler.Default;

    // await a completed task => will continue synchronously
    await SomeFastAsyncOperation().ConfigureAwait(false);

    // await a slow task => will continue in another thread
    var t = await SomeSlowAsyncOperation().ConfigureAwait(false);

    // switch to main thread
    await _joinableTaskFactory.SwitchToMainThreadAsync();

    // write text to text box
    textBox1.Text = t;
}

Using the JoinableTaskFactory from Microsoft.VisualStudio.Threading (NuGet package here), we are able to "switch" back to the UI thread.

As the namespace implies, Microsoft.VisualStudio.Threading originates from the Visual Studio team. I stumbled over this library while reading the documentation for Visual Studio extensibility. Visual Studio is quite a complex application, and there are myriads of extensions available. To improve the start-up time, Microsoft strongly recommends to make use of asynchronous programming (see How to: Manage multiple threads in managed code and How to: Use AsyncPackage to load VSPackages in the background)

I won't go into details of how async/await works. Basically, the compiler generates a state machine, which Dixin explains pretty good in his blog serie Understanding C# async / await (1) Compilation (Part 2, Part 3).

In our case, two calls are interesting:

  1. await TaskScheduler.Default; will continue the succeeding code in a threadpool thread
    (actually, the library provides an extension method GetAwaiter(this TaskScheduler this). This works because the compiler uses a naming convention instead of requiring an interface implemenntation)
  2. await _joinableTaskFactory.SwitchToMainThreadAsync(); will continue the succeeding code in the main thread
    (actually, in the thread with instantiated _joinableTaskFactory).

As you could see, Microsoft.VisualStudio.Threading makes asynchronous programming in desktop applications, both WinForms and WPF, much simpler.

BTW, I've learned a lot reading the code of that library. It provides much more async helpers like AsyncEventHandlers.

Here are some more links if you want to learn more about async programming:

crossthreadingtests's People

Contributors

thoemmi avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.