A Custom Thread Pool Implementation Using C#






2.07/5 (10 votes)
This article describes a custom thread pool implementation using the .NET Framework and C# 3.0.
Introduction
The .NET Framework BCL contains a very nice implementation of a thread pool (the System.Threading.ThreadPool
class).
But, this class is not suitable for the following scenarios:
- Long-running operations. Usually, for long-running operations, it is recommended to use the
Thread
class. ThreadPool
is per process. It means that a situation when there is no available thread in theThreadPool
can happen pretty often. What if you have a very important and emergent work item and do not want to take such a risk? But pretty often, especially when you have an application with a number of app domains (like IIS or SQL server), you can run out of threads in the thread pool...ThreadPool
does not supportIAsyncResult
.BeginInvoke
methods of all delegates internally pass control toThreadPool
, butThreadPool
itself does not supportIAsyncResult
.
Generally, there are number of strict recommendations about when you should use ThreadPool
and when you should use the Thread
class directly or MulticastDelegate.BeginInvoke
. The main problem of System.Threading.ThreadPool
is that it is per process. So, if you have a set of very important tasks to do, and also have a set of third-party assemblies that you host in the application, there is always a probability that your important tasks will be delayed. In the case of the CustomThreadPool
, you have a separate threadpool for each application domain.
You can have as many CustomThreadPool
s as application domains.
This is just the initial version of CustomThreadPool
, and I plan to extend it in future. Maybe, instead of WaitHandle
s, I will use Monitor.Wait
and Monitor.Pulse
to achieve better flexibility (and probably performance).
Using the Code
The CustomThreadPool
has three methods: QueueUserWorkItem
, QueueUserWorkItemResult<tresult>
, and RetreiveUserWorkItemResult
.
A sample of how to use these methods is provided below:
public static class Program
{
//main entry point
public static void Main()
{
//schedule of
CustomThreadPool.QueueUserWorkItem(DoSomething);
CustomThreadPool.QueueUserWorkItemResultt<int>(MyLongRunningFunc,
MyLongRunningFuncFinished);
}
//my long-running task
private static void DoSomething()
{
Console.WriteLine("Hello, world!");
}
//my long-running function
private static int MyLongRunningFunc()
{
return 888;
}
//CustomThreadPool supports IAsyncResult
private static void MyLongRunningFuncFinished(IAsyncResult result)
{
Console.WriteLine(CustomThreadPool.RetreiveUserWorkItemResult<int>(result));
}
}
Points of Interest
I've learned a lot about multithreading, especially about volatile fields and IAsyncResult
implementation.
History
- 20 Nov, 2008 -- Initial Posting
- 10 Mar, 2009 -- Added dispose functionality to
CustomThreadPool
. Class changed from static to "instanceable" to support creation of multiple instances within the same App Domain.