C# Threadpool

Summary: in this tutorial, you’ll learn how to use the C# Threadpool class to manage threads more efficiently.

Introduction to the C# Threadpool

In the previous tutorial, you learned how to develop multithreaded applications by manually creating threads using the Thread class.

Typically, the number of threads that the application need is unknown beforehand. Also, the optimal number of threads that an application should have depends on some external factors including:

  • The number of CPU cores.
  • The type of tasks that need to be executed.
  • System performance.

If you don’t consider these factors carefully, you may overload the system.

A solution to this problem is to use a thread pool.

By definition, a thread pool is managed pool of threads that can be used to execute tasks concurrently. The threads managed by the thread pool are often called worker threads. The worker threads are optimized for short-running tasks. Also, the worker threads are background threads.

The thread pool works as follows:

  • First, a thread pool spawns a number of threads upfront.
  • Second, when you submit a task to a thread pool, the thread pool adds the task to a queue and assigns a thread from a pool to execute the task.
  • Third, once the thread completes the task, the thread pool returns the thread to the pool, ready for executing the next task.

By doing this, the thread pool can reuse threads and avoid the overhead of creating and destroying threads for each task, which is very expensive in terms of time and resources.

The following picture illustrates how the thread pool works:

To create a thread pool, you use the ThreadPool class. The ThreadPool class provides you with the QueueUserWorkItem for submitting tasks to the thread pool.

The QueueUserWorkItem method queues a method for execution. In other words, the method executes when a thread in the thread pool is ready for execution.

The QueueUserWorkItem method accepts an instance of the WaitCallback delegate with the following signature.

public delegate void WaitCallback(object? state);Code language: C# (cs)

In the WaitCallback delegate, the state argument is an object that contains information used by the callback.

C# Threadpool example

The following example demonstrates how to use the ThreadPool class to create a thread pool:

using static System.Console;

static void CheckHttpStatus(string url)
{
    HttpClient client = new();
    var response = client.GetAsync(url).Result;
    WriteLine($"The HTTP status code of {url} is {response.StatusCode}");

}

List<string> urls = new(){
    "https://www.google.com/",
    "https://www.duckduckgo.com/",
    "https://www.yahoo.com/",
};

foreach (var url in urls)
{
    ThreadPool.QueueUserWorkItem((state) => CheckHttpStatus(url));
}


// wait for all thread to complete
// and press a key
Console.Read();Code language: C# (cs)

How it works.

First, define a static method CheckHttpStatus to check the HTTP status code of an URL:

static void CheckHttpStatus(string url)
{
    HttpClient client = new();
    var response = client.GetAsync(url).Result;
    WriteLine($"The HTTP status code of {url} is {response.StatusCode}");
}Code language: C# (cs)

Second, create a list of URLs to check:

List<string> urls = new(){
    "https://www.google.com/",
    "https://www.duckduckgo.com/",
    "https://www.yahoo.com/",
};Code language: C# (cs)

Third, check the HTTP status code of each URL of the list by passing a lambda expression to the QueueUserWorkItem() method of the ThreadPool method:

foreach (var url in urls)
{
    ThreadPool.QueueUserWorkItem((state) => CheckHttpStatus(url));
}Code language: C# (cs)

Finally, add the Console.Read() that blocks the main thread to wait for all threads in the thread pool to be completed.

It’s important to note that you can wait for all the tasks to be completed but we’ll cover it in the subsequent tutorial.

Summary

  • Use a thread pool to improve the application’s performance by making efficient use of available resources and reducing the overhead of creating and destroying threads.
  • Use the ThreadPool class to create a thread pool.
  • Use the QueueUserWorkItem method of the ThreadPool class to submit tasks to the thread pool.
Was this tutorial helpful ?