The Microsoft .NET Base Class Library provides several ways to create a thread and start it. Basically the invocation is very similar to every other one providing the same kind of service: create an object representing an execution flow (or more), assign it a delegate representing the execution flow to execute and, eventually, depending on delegate signature, an object as a parameter.
Well, there are two approaches (essentially):
1) Using the System.Threading.Thread
class.
Thread curr = new Thread(myfunction); /* In a class, myfunction is a void taking an object */
curr.Start(new Object()); /* Or something else to be downcast */
2) Using the System.Threading.ThreadPool
class.
ThreadPool.QueueUserWorkItem(myfunction, new Object()); /* Same philosophy here */
Are there any special reasons why I should use 1) or 2)?
- Performance reasons?
- Patterns?
- What is the best approach?
I have a feeling that the answer is: "Depend by the situation". Could you please list some situations where one approach is better than another?
Starting a new thread can be a very expensive operation. The thread pool reuses threads and thus amortizes the cost. Unless you need a dedicated thread, the thread pool is the recommended way to go. By using a dedicated thread you have more control over thread specific attributes such as priority, culture and so forth. Also, you should not do long running tasks on the thread pool as it will force the pool to spawn additional threads.
In addition to the options you mention .NET 4 offers some great abstractions for concurrency. Check out the Task and Parallel classes as well as all the new PLINQ methods.
The Managed Thread Pool has some very good guidelines on when NOT to use the thread pool.
In my experience, you want to create your own thread when you need a persistent, dedicated, long-running thread. For everything else, use asynchronous delegates or something like QueueUserWorkItem
, BackgroundWorker
, or the Task-related features of .NET 4.0.
Threads in ThreadPool are background threads;
All threads created and started by a new Thread object are foreground threads.
A background thread does not keep the managed execution environment running.
refer to http://msdn.microsoft.com/en-us/library/h339syd0.aspx for more.
In .NET 4.5.2 they added a new method: HostingEnvironment.QueueBackgroundWorkItem.
This appears to be an alternative to ThreadPool.QueueUserWorkItem
. Both behave similarly, but there are some nice benefits to using the new method when working in ASP.NET:
The HostingEnvironment.QueueBackgroundWorkItem method lets you
schedule small background work items. ASP.NET tracks these items and
prevents IIS from abruptly terminating the worker process until all
background work items have completed. This method can't be called
outside an ASP.NET managed app domain.
Using the ThreadPool, you have less control of the threading system. This is a trade off to simplify the process for you. If you have all that you need from the ThreadPool, you should feel free to utilize it. If you need more control of the threads, then you need to of course use the Thread classes.
ThreadPool.QueueUserWorkItem() is basically for fire-and-forget scenarios, when application doesn't depend on whether operations will finish or not.
Use classic threads for fine-grained control.
You should use ThreadPool.QueueUserWorkItem
except in cases of:
You require a foreground thread.
You require a thread to have a particular priority.
You have tasks that cause the thread to block for long periods of
time. The thread pool has a maximum number of threads, so a large
number of blocked thread pool threads might prevent tasks from
starting.
You need to place threads into a single-threaded apartment. All
ThreadPool threads are in the multithreaded apartment.
You need to have a stable identity associated with the thread, or to
dedicate a thread to a task.
Reference link.