Real world software uses concurrency. As you know concurrency has several advantages, main thing is it simulates several things in one time concept. .NET gives three ways for the developers to achieve concurrency while we write code. They are:
These are very low level elements of concurrency. They have their own stack and OS level resources.
Dont confuse .NET Threads with OS threads actually Threads in .NET are CLR managed ones. We should technically call these threads as “CLR Threads”. Sometimes we call them as ‘Virtual Threads” while calling OS/kernal threads as “Physical Threads”.
When it comes to relationship between physical (kernal) and virtual (managed) threads, there is a one to many relationship between them. One managed thread can use one or more OS (kernal) threads. Its up to the Managed Scheduler to decide. So a managed thread could use a Windows Fiber to achieve its execution instead of Windows Threads.
Managed threads provides highest degree of control to developers where we can
Resume() threads even these are not a good practices. But they are costly, since they consume an unpredictable amount of memory in stack and they add additional processing overheads since context switch between threads.
In C#, you can do
And even you can
uiThread.Abort(). Currently there is no alternative for
Thread in .NET with the highest degree of control. There is no maximum number of Threads in .NET, you can use as maximum as your resources allows you to do.
In Visual Studio you can debug threads in the application execution. When your application is running, go to Debug -> Windows -> Threads. In this windows you can search for an specific thread, group and short threads and freeze or thew threads. You can learn more about Threads Window here.
ThreadPool is a collection of fixed numbered threads during the initialization of the application and then reuse them for new tasks then required. Now every executable has a fixed number of threads in them depending in the available free memory.
ThreadPool uses a fixed number of threads every-time they won’t let used memory to grow dramatically like Threads do, there are safer than
Threads. ThreadPools uses a queue that have Tasks and pick Tasks from the queue, execute them and once completed put those tasks to another queue that contains the completed tasks.
We can use
System.Threading.ThreadPool to create thread pools in .NET and no need to specify how many threads should be there is the pool.
ThreadPool manages itself.
ThreadPool class does the following activities
- Execute tasks
- post work items
- Process asynchronous I/O
- Wait on behalf of other threads
- Process timers
We can implement ThreadPool as below
this will give output like
If we comment
Thread.Sleep(1000); line, you can notice, Main thread exits before thread pool method gets executed. Using this we can understand
ThreadPool used background threads they wont keep the program running once all foreground threads get terminated.
You can define the number of threads to be handled in Threadpool via
ThreadPool.SetMinThreads but its a best practice not to set them and let CLR handles with the default value. In .NET 2.0 and 3.0 the default value of MaxThread has a direct relation with the CPU cores. In .NET 2.0, it was 50 times of CPU cores and in .NET 3.0 it was 250 times of CPU cores but after .NET 4.0 it depends on several other factors also such as the size of virtual address space. You can always determine this by calling
ThreadPool.GetMaxThreads. Another useful method is
Conclusion is, concurrency in .NET is sexy but you have to be very careful when you handle this, else you will end up in a total disaster. Despite, having some limitations, Threadpool has more advantages over Threads but Tasks are the best practice when we think about concurrency in .NET still they have more limitations yet they are safer than Threadpool or Thread. I will cover them in next post.