Using ThreadPools in Windows Applications

Introduction

Developers frequently need to perform tasks in their applications that are not instantaneous.

To support such scenarios, Windows developers can use thread pools to execute work in parallel threads that execute asynchronously from the main thread. A thread pool can be considered as a work manager that has a bunch of worker threads. The ThreadPool class assigns work in a queue fashion. As soon as a thread completes a task, it becomes available and ThreadPool picks up the next work item from the queue to execute. This prevent blocking the UI thread, which is a very important part of the user experience.

In addition, thread pools can be used to control the priority of work items and even remove them from the queue. Work items can be scheduled to use timers and periodic timers. For critical work items, ThreadPool can be used to allocate specific resources that ensure that these tasks do not starve for cycle time. Finally, thread pools support running work items in response to named events and semaphores.

Because thread pools run at the OS level, they are more efficient than user-initiated thread management.

Hands On

For our demo, we will create a simple Windows application that exercises common scenarios involving ThreadPool.

Create a new Visual Studio 2013 project using the Blank App (Windows) template.

Pool1
Figure 1: Creating a new project

Add a new control to the default XAML page of the application, MainPage, as shown below.

Pool2
Figure 2: Adding controls

The XAML for the above controls looks like this:

<Page
   x_Class="Win81ThreadPoolDemo.MainPage"
   
   xmlns_x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns_local="using:Win81ThreadPoolDemo"
   xmlns_d="http://schemas.microsoft.com/expression/blend/
      2008"
   xmlns_mc="http://schemas.openxmlformats.org/
      markup-compatibility/2006"
   mc_Ignorable="d">

   <Grid Background="{ThemeResource
         ApplicationPageBackgroundThemeBrush}">
      <Button x_Name="buttonScenario1SubmitWorkItemToThreadPool"
         Content="Submit work item to threadpool"
         HorizontalAlignment="Left" Margin="718,107,0,0"
         VerticalAlignment="Top" Width="383" />
      <TextBlock HorizontalAlignment="Left" Margin="335,122,0,0"
         TextWrapping="Wrap" Text="Scenario 1 - Submit a work item"
         VerticalAlignment="Top"/>
      <TextBox x_Name="textBoxDesiredPrimeNumberLocation"
         HorizontalAlignment="Left" Margin="574,110,0,0"
         TextWrapping="Wrap"
         Text="1000" VerticalAlignment="Top" InputScope="Number"/>
      <TextBox x_Name="textBoxStatus" HorizontalAlignment="Left"
         Margin="658,513,0,0" TextWrapping="Wrap" Text="Status"
         VerticalAlignment="Top" Width="469"/>
      <TextBlock HorizontalAlignment="Left"
         Margin="335,207,0,0" TextWrapping="Wrap"
         Text="Scenario 2 - Submit workitem using timer"
         VerticalAlignment="Top"/>
      <TextBox x_Name="textBoxTimer" HorizontalAlignment="Left"
         Margin="574,207,0,0" TextWrapping="Wrap" Text="1000"
         VerticalAlignment="Top" InputScope="Number"/>
      <Button x_Name="buttonScenario2SubmitWorkitemUsingTimer"
         Content="Submit work item using timer"
         HorizontalAlignment="Left" Margin="721,192,0,0"
         VerticalAlignment="Top" Width="380" />
      <TextBlock HorizontalAlignment="Left" Margin="282,307,0,0"
         TextWrapping="Wrap"
         Text="Scenario 3 - Submit workitem using periodic timer"
         VerticalAlignment="Top"/>
      <TextBox x_Name="textBoxPeriodicTimer"
         HorizontalAlignment="Left" Margin="574,291,0,0"
         TextWrapping="Wrap" Text="1" VerticalAlignment="Top"
         InputScope="Number"/>
      <Button x_Name="buttonScenario3SubmitWorkitemUsingPeriodicTimer"
         Content="Submit work item using periodic timer"
         HorizontalAlignment="Left" Margin="721,285,0,0"
         VerticalAlignment="Top" Width="380" />

   </Grid>
</Page>

Next, we will implement using ThreadPool by using various approaches. In the first approach, we will add a workitem to the thread pool for async execution. We will do this via the click event handler for Button for Scenario 1, called “Submit Work Item to Threadpool”.

But first, we need to add a variable of type IAsyncAction to the class.

public sealed partial class MainPage : Page
{
   private IAsyncAction m_workItem;
   public MainPage()
   {
      this.InitializeComponent();
   }

Next, we implement the click event handler for Scenario 1. In this method, we call the ThreadPool.RunAsync method and pass it the logic to execute in the async task. In this method, we also provide the command to update the UI when the task is completed.

private void buttonScenario1SubmitWorkItemToThreadPool_Click
   (object sender, RoutedEventArgs e)
{
   ulong desiredPrimeNumberLocation =
      ulong.Parse(textBoxDesiredPrimeNumberLocation.Text);
   ulong nthPrime = 0;
   IAsyncAction asyncAction =
      Windows.System.Threading.ThreadPool.RunAsync(
      (workItem) =>
      {
         uint primes = 0;    // Number of primes found so far.
         ulong i = 2;        // Number iterator.

         if ((desiredPrimeNumberLocation >= 0) &&
         (desiredPrimeNumberLocation <= 2))
         {
            nthPrime = desiredPrimeNumberLocation;
            return;
         }
         // lame prime number detection logic
         while (primes < (desiredPrimeNumberLocation - 1))
         {
            i++;
            // Check for prime.
            bool prime = true;
            for (uint j = 2; j < i; ++j)
            {
               if ((i % j) == 0)
               {
                  prime = false;
                  break;
               }
            };

            if (prime)
            {
               primes++;
            }
         }

         // Return the nth prime number.
         nthPrime = i;
      });

   m_workItem = asyncAction;

   // logic to print the result when the task is complete
   asyncAction.Completed = new AsyncActionCompletedHandler(
      (IAsyncAction asyncInfo, AsyncStatus asyncStatus) =>
      {

         String status = "\n" + "The " + desiredPrimeNumberLocation
            + "th prime number is "
            + nthPrime + ".\n";

         // Update the UI thread with the CoreDispatcher.
         CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
            CoreDispatcherPriority.High,
            new DispatchedHandler(() =>
            {
                textBoxStatus.Text = status;
            }));
         });
      }

ThreadPool can also be used by creating work items using timers. This can be done by using the ThreadPoolTimer.CreateTimer API. Here is the click event handler for the button for Scenario 2 – Submit work item using Timer.

private void buttonScenario2SubmitWorkitemUsingTimer_Click
   (object sender, RoutedEventArgs e)
{
   TimeSpan delay = TimeSpan.FromMilliseconds
      (double.Parse(textBoxTimer.Text));
   ThreadPoolTimer DelayTimer = ThreadPoolTimer.CreateTimer(
      async (timer) =>
      {
         await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
         () =>
         {
            textBoxStatus.Text = "Scenario 2 completed";
         });
      },
      delay);
   }

Thread pools also can be used for periodic timers where you want to be apprised at every interval. This can be done by using the ThreadPoolTimer.CreatePeriodicTimer API. We will use it for the event handler for the button for Scenario 3.

private void buttonScenario3SubmitWorkitemUsingPeriodicTimer_Click
   (object sender, RoutedEventArgs e)
{
   int count = 0;
   TimeSpan delay = TimeSpan.FromSeconds(double.Parse
      (textBoxPeriodicTimer.Text));
   ThreadPoolTimer PeriodicTimer =
      ThreadPoolTimer.CreatePeriodicTimer(
      async (timer) =>
      {
         await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
         () =>
         {
            count++;
            textBoxStatus.Text = "Scenario 3 called. Count "
               + count.ToString() ;
         });
      },
      delay);
   }

Our application is now complete. We now can run the application. When the specific task is complete, or the specific time has elapsed in the execution of the task, the status text is updated.

You can download a sample of this code at the bottom of this article.

Summary

In this article, we learned about thread pool basics and how to build a simple Windows application that uses thread pools to perform asynchronous tasks.

Reference

https://msdn.microsoft.com/library/windows/apps/hh465290?f=255&MSPPError=-2147217396

About the Author

Vipul Patel is a technology geek based in Seattle. He can be reached at vipul.patel@hotmail.com. You can visit his LinkedIn profile at https://www.linkedin.com/pub/vipul-patel/6/675/508.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read