DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 15.9 Determining Whether a Requestfor a Pooled Thread Will Be Queued

Problem

Your application will be creating many threads from the thread pool. When creating a thread from this pool, you want to be informed as to whether a thread in the pool is available or if none are available, and the request for a new thread will have to be queued. Basically, you want to know whether a thread is available for immediate use from the thread pool.

Solution

Use the ThreadPool.GetAvailableThreads method to get the number of worker threads currently available in the ThreadPool to determine whether you should queue another request to launch another thread via ThreadPool.QueueUserWorkItem or take an alternate action. The Main method calls a method (SpawnManyThreads) to spawn lots of threads to do work in the ThreadPool, then waits for a bit to simulate processing:

public class TestThreads
{
    public static void Main( )
    {
        SpawnManyThreads( );
        // have to wait here or the background threads in the thread
        // pool would not run before the main thread exits.
        Console.WriteLine("Main Thread waiting to complete...");
        Thread.Sleep(2000);
        Console.WriteLine("Main Thread completing...");
    }

The SpawnManyThreads method launches threads and pauses between each launch to allow the ThreadPool to register the request and act upon it. The isThreadAvailable method is called with the parameter set to true to determine whether there is a worker thread available for use in the ThreadPool:

public static bool SpawnManyThreads( )
{
    try
    {
        for(int i=0;i<500;i++)
        {
            // have to wait or threadpool never gives out threads to 
            // requests
            Thread.Sleep(100);
            // check to see if worker threads are available in the pool
            if(true == isThreadAvailable(true))
            {
                // launch thread if queue isn't full
                Console.WriteLine("Worker Thread was available...");
                ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),i);
            }
            else
                Console.WriteLine("Worker Thread was NOT available...");
        }
    }
    catch(Exception e)
    {
        Console.WriteLine(e.ToString( ));
        return false;
    }
    return true;
}

The isThreadAvailable method calls ThreadPool.GetAvailableThreads to determine whether the ThreadPool has any available worker threads left. If you pass false as the checkWorkerThreads parameter, it also sees whether there are any completion port threads available. The GetAvailableThreads method compares the current number of threads allocated from the pool against the maximum ThreadPool threads. The worker thread maximum is 25 per CPU, and the completion port thread maximum is 1,000 total, regardless of CPUs on v1.1 of the CLR:

public static bool isThreadAvailable(bool checkWorkerThreads)
{
    int workerThreads = 0;
    int completionPortThreads = 0;
    // get available threads
    ThreadPool.GetAvailableThreads(out workerThreads,out completionPortThreads);

    // indicate how many work threads are available
    Console.WriteLine("{0} worker threads available in thread pool.",
                            workerThreads);

    if(checkWorkerThreads)
    {
        if(workerThreads > 0)
            return true;
    }
    else // check completion port threads
    {
        if(completionPortThreads > 0)
            return true;
    }
    return false;
}

This is a simple method to call in a threaded fashion:

static void ThreadProc(Object stateInfo) 
    {
        // show we did something with this thread
        Console.WriteLine("Thread {0} running...",stateInfo);
        Thread.Sleep(1000);
    }
}

Discussion

The ThreadPool is a great way to perform background tasks without having to manage all aspects of the thread yourself. It can be handy to know when the ThreadPool itself is going to become a bottleneck to your application, and the GetAvailableThreads method can help you. However, you might want to check your application design if you are consistently using this many threads as you might be losing performance due to contention or context switching. Queuing up work when the ThreadPool is full simply queues it up for execution once one of the threads comes free; the request isn't lost, just postponed.

See Also

See the "ThreadPool Class" topic in the MSDN documentation. Also see Applied Microsoft .NET Framework Programming by Jeffrey Richter (Wintellect).

    [ Team LiB ] Previous Section Next Section