Threading — using the ThreadPool vs. creating your own threads

There are a lot of dis­cus­sions on the pros and cons of using the Thread­Pool and cre­at­ing your own threads. Hav­ing spent a bit of time read­ing what oth­ers have to say, here’s a sum­ma­ry of the things I’ve picked up on.

The problem with creating your own threads

Cre­at­ing and destroy­ing threads has a high CPU usage, so when you need to per­form lots of small, sim­ple tasks con­cur­rent­ly the over­head of cre­at­ing your own threads can take up a sig­nif­i­cant por­tion of the CPU cycles and severe­ly affect the final response time. This is espe­cial­ly true in stress con­di­tions where exe­cut­ing mul­ti­ple threads can push CPU to 100% and most of the time would be wast­ed in con­text switch­ing (swap­ping threads in and out of the proces­sor along with their mem­o­ry).

Using the Thread Pool

This is where the .Net Thread Pool comes in, where a num­ber of threads are cre­at­ed ahead of time and kept around to pick up any work items you give them to do, with­out the over­head asso­ci­at­ed with cre­at­ing your own threads.

When not to use the Thread Pool

In an ide­al world you would always want to use the Thread Pool, but there are some real-world lim­i­ta­tions. Most impor­tant­ly, and the rea­son why most experts would tell you not to use the Thread Pool except for brief jobs is that: there is a lim­it­ed num­ber of threads in the .Net Thread Pool (250 per CPU by default), and they are being used by many of the .Net frame­work class­es (e.g. timer events are fired on thread pool threads) so you wouldn’t want your appli­ca­tion to hog the thread pool.

There are also a num­ber of sit­u­a­tions where you shouldn’t use the thread pool:

  • You require a fore­ground thread, all the thread pool threads are back­ground threads
  • You require a thread to have a par­tic­u­lar pri­or­i­ty.
  • You have tasks that cause the thread to block for long peri­ods of time. The thread pool has a max­i­mum num­ber of threads, so a large num­ber of blocked thread pool threads might pre­vent tasks from start­ing.
  • You need to place threads into a sin­gle-thread­ed apart­ment. All Thread­Pool threads are in the mul­ti­thread­ed apart­ment.
  • You need to have a sta­ble iden­ti­ty asso­ci­at­ed with the thread, or to ded­i­cate a thread to a task.

Excep­tions in Thread Pool threads

Unhan­dled excep­tions on thread pool threads ter­mi­nate the process with 3 excep­tions:

When to create your own threads

As I’ve men­tioned already, cre­at­ing your own threads is bad when lots of sim­ple tasks require a rel­a­tive large over­head in con­text switch­ing, and the Thread Pool is bad for long run­ning, or block­ing tasks. Which leads to the nat­ur­al con­clu­sion :-P – cre­ate your own threads for long run­ning, or block­ing tasks!

Parting thoughts…

When work­ing with the Thread Pool there are some use­ful meth­ods at your dis­pos­able, includ­ing:

  • GetAvail­ableThreads method which returns the num­ber of threads avail­able to you
  • Get­MinThreads method returns the num­ber of idle threads the thread pool main­tains in antic­i­pa­tion of new requests
  • Get­Max­Threads method returns the max num­ber of thread pool threads that can be active con­cur­rent­ly
  • Set­MinThreads method sets the num­ber of idle threads the thread pool main­tains in antic­i­pa­tion of new requests
  • Set­Max­Threads method sets the num­ber of thread pool threads that can be active con­cur­rent­ly

If you’re inter­est­ed in how the Thread­Pool class dynam­i­cal­ly man­ages the size of the thread pool under the hood (despite giv­ing you the option to set min and max threads) you should have a read of Pedram Razai’s blog post in the ref­er­ence sec­tion.

And before you go, I men­tioned ear­li­er that all Thread Pool threads are back­ground threads, so how do they dif­fer from fore­ground threads? Well, fore­ground and Back­ground threads are iden­ti­cal with one excep­tion: a back­ground thread does not keep the man­aged exe­cu­tion envi­ron­ment run­ning. Once all fore­ground threads have been stopped in a man­aged process (where the .exe file is a man­aged assem­bly), the sys­tem stops all back­ground threads and shuts down.

References:

Stack­Over­flow ques­tion on Thread Pool vs Thread Spawn­ing

Anoth­er Stack­Over­flow ques­tion on Thread Pool vs Thread Spawn­ing

Stack­Over­flow ques­tion on when to use the Thread Pool in C#


Stack­Over­flow ques­tion on man­ag­ing the size of the Thread Pool in C#

Stack­Over­flow ques­tion with detail on the throt­tling behav­iour of the Thread­Pool

MSDN arti­cle on The Man­aged Thread Pool

MSDN C# Pro­gram­ming Guide : how to use a Thread­Pool

MSDN arti­cle on why we need a thread pool

Jon Skeet’s intro­duc­to­ry arti­cle on Mul­ti-thread­ing in C#

Pedram Rezaei’s blog post on ded­i­cat­ed threads vs thread­pool threads

Smart Thread Pool project on Code­Plex