How to: Use a Thread Pool (C# Programming Guide)

A thread pool is a collection of threads that can be used to perform several tasks in the background. (See Using Threading (C# Programming Guide) for background information.) This leaves the primary thread free to perform other tasks asynchronously.

Thread pools are often employed in server applications. Each incoming request is assigned to a thread from the thread pool, so that the request can be processed asynchronously, without tying up the primary thread or delaying the processing of subsequent requests.

Once a thread in the pool completes its task, it is returned to a queue of waiting threads, where it can be reused. This reuse enables applications to avoid the cost of creating a new thread for each task.

Thread pools typically have a maximum number of threads. If all the threads are busy, additional tasks are put in queue until they can be serviced as threads become available.

You can implement your own thread pool, but it is easier to use the thread pool provided by the .NET Framework through the ThreadPool class.

The following example uses the .NET Framework thread pool to calculate the Fibonacci result for ten numbers between 20 and 40. Each Fibonacci result is represented by the Fibonacci class, which provides a method named ThreadPoolCallback that performs the calculation. An object that represents each Fibonacci value is created, and the ThreadPoolCallback method is passed to QueueUserWorkItem, which assigns an available thread in the pool to execute the method.

Because each Fibonacci object is given a semi-random value to compute, and because each thread will be competing for processor time, you cannot know in advance how long it will take for all ten results to be calculated. That is why each Fibonacci object is passed an instance of the ManualResetEvent class during construction. Each object signals the provided event object when its calculation is complete, which allows the primary thread to block execution with WaitAll until all ten Fibonacci objects have calculated a result. The Main method then displays each Fibonacci result.

Example

using System;
using System.Threading;

public class Fibonacci
{
    public Fibonacci(int n, ManualResetEvent doneEvent)
    {
        _n = n;
        _doneEvent = doneEvent;
    }

    // Wrapper method for use with thread pool. 
    public void ThreadPoolCallback(Object threadContext)
    {
        int threadIndex = (int)threadContext;
        Console.WriteLine("thread {0} started...", threadIndex);
        _fibOfN = Calculate(_n);
        Console.WriteLine("thread {0} result calculated...", threadIndex);
        _doneEvent.Set();
    }

    // Recursive method that calculates the Nth Fibonacci number. 
    public int Calculate(int n)
    {
        if (n <= 1)
        {
            return n;
        }

        return Calculate(n - 1) + Calculate(n - 2);
    }

    public int N { get { return _n; } }
    private int _n;

    public int FibOfN { get { return _fibOfN; } }
    private int _fibOfN;

    private ManualResetEvent _doneEvent;
}

public class ThreadPoolExample
{
    static void Main()
    {
        const int FibonacciCalculations = 10;

        // One event is used for each Fibonacci object
        ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
        Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
        Random r = new Random();

        // Configure and launch threads using ThreadPool:
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
        for (int i = 0; i < FibonacciCalculations; i+)
        {
            doneEvents[i] = new ManualResetEvent(false);
            Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
            fibArray[i] = f;
            ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
        }

        // Wait for all threads in pool to calculation...
        WaitHandle.WaitAll(doneEvents);
        Console.WriteLine("All calculations are complete.");

        // Display the results... 
        for (int i= 0; i<FibonacciCalculations; i+)
        {
            Fibonacci f = fibArray[i];
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
        }
    }
}

Here is the output:

launching 10 tasks...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
result calculated...
all calculations complete
Fibonacci(22) = 17711
Fibonacci(25) = 75025
Fibonacci(32) = 2178309
Fibonacci(36) = 14930352
Fibonacci(32) = 2178309
Fibonacci(26) = 121393
Fibonacci(35) = 9227465
Fibonacci(23) = 28657
Fibonacci(39) = 63245986
Fibonacci(22) = 17711

See Also

Tasks

Monitor Synchronization Technology Sample

Wait Synchronization Technology Sample

Concepts

C# Programming Guide

Monitors

Reference

Threading (C# Programming Guide)

Using Threading (C# Programming Guide)

Mutex

WaitAll

ManualResetEvent

Set

ThreadPool

QueueUserWorkItem

ManualResetEvent

Other Resources

HOW TO: Synchronize Access to a Shared Resource in a Multithreading Environment by Using Visual C# .NET

Security in the .NET Framework