By: Artemakis Artemiou | Updated: 2019-04-29 | Comments | Related: > Application Development
Problem
In my previous Application Development tips we’ve talked about the different multithreading options available in .NET Framework. To this end, we’ve talked about the BackgroundWorker class, the Thread class, the ThreadPool class and the Task Parallel Library, also known as TPL.
As you can see, there is more than one option for implementing multithreading in .NET. This is a fact that naturally leads to the question: "which multithreading technique should I use when I develop .NET apps?".
In this tip, we will try to answer this question.
Solution
So, which multithreading technique should we be using when developing applications in .NET?
The simple answer to this question is "it depends".
To be able to better identify the cases where each one of the available multithreading techniques should be used, first we need to compare the 4 multithreading options in .NET, see what they can offer and then further discuss.
Thread Class
The Thread class in .NET, allows to create and control a thread, set its priority, and get its state.
The main code to create and use a Thread object is the below:
Thread t; t = new Thread(new ThreadStart(ThreadProc)); t.Start();
Note: in the above code, "ThreadProc" is the method you want to be executed by the thread.
ThreadPool Class
The ThreadPool class has been available in .NET since the beginning along with the Thread class and it is managed by CLR. The ThreadPool class is a wrapper of a pool of threads that can be used to execute tasks, post work items, process asynchronous I/O, wait on behalf of other threads, and process timers.
The main code to use ThreadPool for multithreading in .NET is the below:
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
Note: in the above code, "ThreadProc" is the method you want to be executed by the thread.
BackgroundWorker Class
BackgroundWorker, is a component in .NET Framework, that allows executing code as a separate thread and then report progress and completion back to the UI.
In order to implement a BackgroundWorker-based multithreading .NET app, you include handling code for the below 3 events:
- DoWork
- Occurs when RunWorkerAsync() is called. Within this event, you add the actual code to be executed.
- ProgressChanged
- Occurs when ReportProgress(Int32) is called. This event is used for handling the progress reported by the component.
- RunWorkerCompleted
- Occurs when the background operation has completed, has been canceled, or has raised an exception.
Moreover, with the below 3 methods, you can fully control what’s running within the thread:
- RunWorkerAsync()
- ReportProgress(Int32)
- CancelAsync()
Task Parallel Library (TPL)
The Task Parallel Library (TPL) in .NET, is a set of public types and APIs in the System.Threading and System.Threading.Tasks namespaces. TPL has been created, in order to help developers to easily add parallelism and concurrency in their .NET applications. TPL was originally introduced in .NET 4.0.
A simple way of using TPL, is with the below code/pseudocode:
Parallel.Invoke( () => { //code for parallel task 1 }, () => { //code for parallel task 2 }, () => { //code for parallel task N } );
Note: If you need even more control, TPL allows you to make use of the Task class.
Compare Multithreading Options in .NET
Now let’s compare the above multithreading options and discuss what criteria we can use, in order to choose the most efficient multithreading technique, each time we need to implement multithreading in our .NET apps.
First, let’s talk about the Thread class. The Thread class has been around since the beginning of .NET Framework. It is the older multithreading technique in .NET, as well as the most low-level multithreading approach, since it is very close to the Operating System. One benefit of the Thread class, is that when it is instantiated, it runs on the Foreground by default, therefore, when the main thread ends, the Thread objects still run until they complete execution. On the other hand, Thread objects are difficult to manage. Moreover, it is quite difficult to use this type of multithreading in scenarios where you develop GUI .NET apps.
Now, let’s talk about the ThreadPool class. ThreadPool, unlike the Thread class, is managed by the Common Language Runtime (CLR). This means, that among other, it is the CLR that automatically undertakes the creation and reuse of threads and that is the main benefit of the ThreadPool class. So, unlike in the case of the Thread class, ThreadPool, due to CLR, makes the overall management of Threads easier. On the other hand, the ThreadPool class, along with the QueueUserWorkItem method, does not return a result/outcome of the threads’ execution, therefore it is more suitable for "Run and Forget" scenarios. Another thing to note regarding the ThreadPool class, is that in case the main thread ends, all ThreadPool threads will also end their execution, therefore, you need to take this into consideration and properly manage this case in your code. Last, like the case of the Thread class, it is quite difficult to use this type of multithreading in scenarios where you develop GUI .NET apps.
The BackgroundWorker component was designed, in order to provide the .NET developer with a handy way to run code as a separate thread in GUI environments (i.e. Windows Forms apps), report progress, as well as to add handling code in the event of completion of the BackgroundWorker’s thread. BackgroundWorker is a great option when you develop GUI apps in .NET, for example Windows Forms apps, and you are looking for an easy way to create, run and manage separate processes/threads for different operations along with keeping the main UI and its components updated (i.e. updating a progress bar control), without having your UI freeze each time you execute a long-running process, such as importing a file, etc.
The last multithreading option to talk about, is the Task Parallel Library, also known as TPL. TPL is the latest addition in .NET Framework regarding multithreading/parallelism. TPL combines all the good stuff the Thread and ThreadPool classes have and it is a modern way of running parallel tasks in .NET apps. Therefore, it provides notification capabilities, parallel task control (i.e. continue, wait, etc.) as well as automated management and tuning of threads. Because of that, in many cases of multithreading, TPL can boost performance. On the other hand, in some special cases, multithreading with ThreadPool can be faster, however even in those cases, all the other benefits of TPL make it again a better option.
The last comparison to make in this article, is BackgroundWorker vs TPL for cases where you need to implement multithreading in GUI .NET aps such as Windows Forms apps. In these cases, you can implement the same behavior in terms of multithreading just like the BackgroundWorker, by using TPL. Actually, using TPL will might be even a little bit simpler since you do not need to use events, which is something that some people might find a little bit confusing.
Overall, I would say that TPL is the way forward when it comes to multithreading in .NET. It is a modern multithreading/parallelism mechanism and provides all the "good" elements of the Thread and ThreadPool classes and the BackgroundWorker component. Of course, many developers may still prefer using BackgroundWorker for multithreading in their GUI .NET apps and that is still a great option, since with BackgroundWorker might find it easier to report progress to the UI.
Next Steps
- Check out my tip: Learn how to build a multithreading .NET Application to work with SQL Server
- Check out my tip: .NET Multithreading Example Using Thread Class
- Check out my tip: .NET Multithreading Example Using ThreadPool Class
- Check out my tip: .NET Multithreading Example Using Task Parallel Library
- Check the MS Docs article: Thread Class
- Check the MS Docs article: ThreadPool Class
- Check the MS Docs article: BackgroundWorker Class
- Check the MS Docs article: Task Parallel Library (TPL)
- Check the MS Docs article: System.Threading Namespace
About the author
This author pledges the content of this article is based on professional experience and not AI generated.
View all my tips
Article Last Updated: 2019-04-29