Click here to Skip to main content
Click here to Skip to main content

Wait for threads in a ThreadPool object to complete

By , 27 Sep 2004
 

Introduction

If you use the System.Threading.ThreadPool object, you know you can create many worker threads. The following code snippet waits until all worker threads have completed, or until the specified timeout.

Background

I use the System.Threading.ThreadPool extensively when creating Windows services. I usually spawn a worker thread for every service request. When the user attempts to pause or stop the service, I send a message to all threads to shut down, and then, in my main thread, must wait for all the threads to complete. If the service does not wait for all threads to complete, you get a nasty timeout error from Windows claiming the service 'did not respond'. I believe it is more professional to do the waiting in the service and not expose the user to the error dialog.

There are other ways to wait for all threads to complete, but none are as simple and as elegant as the code snippet below.

Using the code

I usually create a method called WaitForThreads() and define a timeout value (in seconds) as a property of my service class.

I call WaitForThreads() as the last action in my OnStop() and OnPause() methods. The timeout value is there just in case some worker thread misbehaves. An additional advantage to using a timeout is that I get to log all cases where the timeout was used - and fix the worker thread behavior.

/// <summary>
/// Blocks until all worker threads have returned to the thread pool.
/// A good timeout value is 30 seconds.
/// </summary>
protected void WaitForThreads()
{
    int    maxThreads   = 0;
    int    placeHolder  = 0;
    int    availThreads = 0;
    int    timeOutSeconds = YourTimeoutPropertyHere;

    //Now wait until all threads from the Threadpool have returned
    while (timeOutSeconds > 0)
    {
        //figure out what the max worker thread count it
        System.Threading.ThreadPool.GetMaxThreads(out 
                             maxThreads,out placeHolder);
        System.Threading.ThreadPool.GetAvailableThreads(out availThreads, 
                                                       out placeHolder);

        if (availThreads == maxThreads) break;
        // Sleep
        System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(1000));
        --timeOutSeconds;
    }
    // You can add logic here to log timeouts
}

Points of Interest

When creating services, make sure you can interrupt executing threads. It is very difficult to stop a service that has runaway threads. I create a separate class to be used by the worker threads and keep track of each thread in a master collection in my service class. Every worker thread class I have has an Interrupt() method which sets a flag causing the thread to exit.

You can use Thread.Abort to stop threads - but MSDN documentation recommends against it. In my experience, design your worker thread classes with reasonable checkpoints (preferably before starting any lengthy operations), and when you are waiting on a resource, make sure the service class can interrupt the wait.

History

Version 1.0, based on an idea suggested by Jeremy Thomas.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

gtamir
Web Developer
United States United States
Member
Giora Tamir has been Architecting, Designing and Developing software and hardware solutions for over 15 years. As an IEEE Senior member and a talented developer, Giora blends software development, knowledge of protocols, extensive understanding of hardware and profound knowledge of both Unix and Windows based systems to provide a complete solution for both defense and commercial applications. Giora, also known as G.T., now holds the position of Principal Engineer for ProfitLine, Inc. architecting the next generation of .NET applications based on a Service-Oriented-Architecture.
 
Gioras areas of interest include distributed applications, networking and cryptography in addition to Unix internals and embedded programming.
 
Founded in 1992, ProfitLine manages hundreds of millions of dollars in annual telecom spend for its prestigious Fortune 1000 client base, such as Merrill Lynch, Charming Shoppes, Macromedia, CNA Financial Corporation, and Constellation Energy Group. ProfitLine's outsourced solution streamlines telecom administrative functions by combining a best practices approach with intelligent technology. For more information about ProfitLine, call 858.452.6800 or e-mail sales@profitline.com.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionPoolGuardmemberAlsarg723 Dec '11 - 22:05 
You might find this useful. It lets you cleanly wait on your thread pool threads ending.
 
https://bitbucket.org/nevdelap/poolguard
Generalthreadpool doubtmembercarlos_rocha6 Jan '05 - 1:26 
Hi! I've read your article and maybe you know the answer for this.I have an app that does async. requests.Those requests are served by the IOcompletion threads form the threadpool.After the thread ends the thread is returned to the threadpool because the number of available threads equals the max number of threads, but if i pause the app the thread still apears in the thread list(in visual Studio) although the code is not acessible.Shouldn't that thread disapear from the the thread list in Visual Studio?And another thing, there's always a thread with high priority during the life of the app; i've read some where that when there is async requests, a thread exists that checks for requests and events.Is it that thread?
 
Never say never
GeneralIs there any guarantee...memberRolf Schaeuble28 Sep '04 - 4:41 
... that the number of available threads ever equals the maximum number of threads?
The CLR might use the thread pool threads for internal purposes as well -> not only your own threads are running there.
 
Actually, I have always thought that it is a design limitation of the thread pool that it doesn't have a wait-for-completion method that waits for all queued work items to complete.
GeneralRe: Is there any guarantee...membergtamir28 Sep '04 - 4:48 
You are correct, available threads may never equal maximum threads, BUT:
- In my experience, unless you use asynchronous IO, .NET does not use ThreadPool threads for long periods of time.
- This is why there is a timeout in addition to the equality check.
I have been using this method for some time with a variety of services and have had excellent experience with it.
GeneralRe: Is there any guarantee...memberGary DesRoches28 Sep '04 - 4:52 
This is what I thought too. I thought it was a collection of threads which can be used by any process in the OS.
GeneralRe: Is there any guarantee...memberRolf Schaeuble28 Sep '04 - 5:18 
I think that's not correct.
Each process has its own thread pool.
 
However, I think that the thread pool is shared by all app domains in the process. So as soon as more than one app domain exists in a process, the technique described in the article doesn't work reliably any more, since another app domain might still have work items enqueued.
 
The best solution I know of is to maintain a counter of enqueued work items.
Before enqueueing a work item, increase the counter.
As the last command in your work items, decrease the counter, and if it's going down to zero, do something like set a signal for the main thread. This is a simplified description, but you should get the idea...
(Manipulation of the counter must be done thread-safe, via interlocked functions etc.).
 
This still leaves a small race condition between the line decrementing the counter and the actual return from the work item, but that shouldn't matter. At least I don't know of any better solution (except of not using the standard thread pool, but writing your own one that is as efficient as the standard one is probably quite hard).
GeneralRe: Is there any guarantee...membergtamir28 Sep '04 - 9:21 
I am probably very lucky. All the services I have created to date make use of a single app domain per process.
As long as you have a single app domain - the technique described is very reliable.
GeneralRe: Is there any guarantee...memberGary DesRoches28 Sep '04 - 9:54 
Thanks for clearing that up. Smile | :)
GeneralRe: Is there any guarantee...membergtamir28 Sep '04 - 9:24 
The ThreadPool object is a static, per-process object. Worker threads in the ThreadPool are only used by and in the process. As a general rule, unless you invoke some asynchronous .NET call, your code is the only thing using the treads in your process ThreadPool.
GeneralRe: Is there any guarantee...memberphyl4 Oct '04 - 22:02 
What about ansyncron delegate invokations? I throught that they use the ThreadPool. Some Timer-Implemenations of the Framework use the ThreadPool too.
GeneralRe: Is there any guarantee...membergtamir5 Oct '04 - 20:04 
Asynchronous delegate invocations ARE asynchronous I/O operations. My assumption is that before terminating your process (and waiting for threads to complete) you made an attempt to CANCEL all threaded operations. Asynch delegate invocations only consume a thread if you specified you want a callback on completion. Use either IsComplete or WaitOne and you can interrupt the waiting thread using Thread.Interrupt.
For more information about asynchronous delegate invocations see http://msdn.microsoft.com/msdnmag/issues/01/08/async/.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 28 Sep 2004
Article Copyright 2004 by gtamir
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid