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.
protected void WaitForThreads()
{
int maxThreads = 0;
int placeHolder = 0;
int availThreads = 0;
int timeOutSeconds = YourTimeoutPropertyHere;
while (timeOutSeconds > 0)
{
System.Threading.ThreadPool.GetMaxThreads(out
maxThreads,out placeHolder);
System.Threading.ThreadPool.GetAvailableThreads(out availThreads,
out placeHolder);
if (availThreads == maxThreads) break;
System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(1000));
--timeOutSeconds;
}
}
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.
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 <a href=mailto:sales@profitline.com>sales@profitline.com.