When a thread is created:
1. A kernel object is allocated and initialized
2. The thread's stack memory is allocated and initialized,
3. Windows sends every DLL in the process a DLL_THREAD_ATTACH notification, causing pages from disk to be faulted into memory so that code can execute.
When a thread dies:
1. Every DLL is sent a DLL_THREAD_DETACH notification
2. The thread's stack memory is freed
3. The kernel object is freed (if its usage count goes to 0).
So, there is a lot of overhead associated with creating and destroying a thread that has nothing to do with the work that the thread was created to perform in the first place.
Thread Pool can come to rescue here.
There is one thread pool per process; this thread pool is shared by all AppDomains in the process.ThreadPool class is a static class. The CLR's thread pool will automatically create a thread, if necessary, and reuse an exiting thread if possible. Also, this thread is not immediately destroyed; it goes back into the thread pool so that it is ready to handle any other work items in the queue.
1. All the threads in ThreadPool are background threads.
2. All the threads run with normal priority and should not be changed.
3. The threads from ThreadPool should not be aborted.
4. Internally, the thread pool categorizes its threads as either worker threads or I/O threads.
a.
Worker threads are used when your application asks the thread pool to perform an asynchronous compute-bound operation.
b.
I/O threads are used to notify your code when an asynchronous I/O-bound operation has completed.
5. When using ThreadPool's QueueUserWorkItem method to queue an asynchronous operation, the CLR offers no built-in way for you to determine when the operation has completed.
6. If a thread pool thread has been idle for approximately 2 minutes, the thread wakes itself up and kills itself in order to free up resources.
Number of threads in thread poolA thread pool should never place an upper limit on the number of threads in the pool because
starvation or deadlock might occur.
With version 2.0 of the CLR, the maximum number of worker threads default to 25 per CPU in the machine2 and the maximum number of I/O threads defaults to 1000.
If you think that your application needs more than 25 threads per CPU, there is something seriously wrong with the architecture of your application and the way that it's using threads.
Uses of Thread PoolA thread pool can offer performance advantage. It offers the following capabilities
1. Calling a method asynchronously
2. Calling a method at a timed interval
3. Calling a method when a single kernel object is signaled
4. Calling a method when an asynchronous I/O request completes
Calling a Method AsynchronouslyTo queue a task for the thread pool, use the following methods. Using QueueUserWorkItem might make your application more efficient because you won't be creating and destroying threads for every single client request.
public static Boolean QueueUserWorkItem(WaitCallback wc, Object state);
public static Boolean QueueUserWorkItem(WaitCallback wc);
public delegate void WaitCallback(Object state);
Calling a Method at Timed IntervalsThe System.Threading namespace defines the Timer class. When you construct an instance of the Timer class, you are telling the thread pool that you want a method of yours called back at a particular time in the future.
Internally, the CLR has just one thread that it uses for all Timer objects.
If your callback method takes a long time to execute, the timer could go off again. This would cause multiple thread pool threads to be executing your callback method simultaneously. Watch out for this; if your method accesses any shared data, you will probably need to add some thread synchronization locks to prevent the data from becoming corrupted.
Calling a Method When a Single Kernel Object Becomes SignaledUse the Register and Unregister WaitHandle methods.
When not to use Thread Pool thread
1. If I wanted the thread to run at a special priority (all thread pool
threads run at normal priority, and you should not alter a thread pool thread's priority).
2. You want the thread a foreground thread (all thread pool threads are background threads), thereby preventing the application from dying until my thread has completed its task.
3. I'd also use a dedicated thread if the compute-bound task were extremely long running; this way, I would not be taxing the thread pool's logic as it tries to figure out whether to create an additional thread.
4. Finally, I'd use a dedicated thread if I wanted to start a thread and possibly abort it prematurely by calling Thread's Abort method