Dot Net For All

Working with thread pool in C#

I have already discussed about the basics of the thread in my previous article. In this article I will discuss about the working with thread pool in C#. Why do we need thread pool? How to use them in the programming scenarios? And other stuff related to them.

Why thread pool in C#?

Creation and execution of thread in windows programming is always an expensive job. As the thread contains its own stack of data, this can waste lots of the memory resources and also hurts performance due to operating system to make its hands dirty to schedule and context switch between the runable threads.

To negate this process of creation and destroying of thread in windows, CLR contains code to manage  its own thread pool. Thread pool is a set of threads that are available for the application’s own use. There is only one thread pool per CLR, this thread pool is shared by all the AppDomains controlled by the CLR.

If we want to perform some asynchronous operation, we can use the any of the methods(which I have discussed next) to append an entry into thread pool’s queue. If there are no threads in the thread pools queue a new thread is created and once the operation is completed, the threads sits idle  waiting for the other operation to use it and hence this thread is not destroyed.

But if the application is queuing more items then the existing threads to take care of all the operations, more threads are created in the thread pool and a point is reached where no more threads will be created and all the requests will be taken care by the present threads.

Once the thread pool sits ideal for some duration which is based on the CLR setting, the pool starts freeing the threads present and hence releasing the memory resources.

Thread pools are background threads and the IsBackGround property is true of these threads, which means that the process can shut down even if there is some thread in the thread pool running.

The thread creation and consumption is based on the FIFO based methodology. Means that the operation which has requested first for the thread in the thread pool is the one which will be started first but it is not at all guaranteed that we will get the result sequentially.

Whichever operation completes first the, the result of that operation is returned first.

How to create threads in Thread Pool?

In this part of the article I want to discuss the ways in which we can create the threads in the thread pool.

Thread pool using QueueUserWorkItem

One of the way in which we can execute operation in thread pool is using the QueueUserWorkItem method of the Static class ThreadPool which is present under System.Thread.

public static bool QueueUserWorkItem(WaitCallback callBack);
public static bool QueueUserWorkItem(WaitCallback callBack, object state);

In the below code I have created an operation in the thread pool using the QueueUserWorkItem which takes a delegate of type WaitCallBack which has one parameter of object type.

        static void Main(string[] args)
        {        
            ThreadPool.QueueUserWorkItem(ThreadPoolOperation, 5);
            Console.WriteLine("In the main thread");
            Console.Read();
        }

        private static void ThreadPoolOperation(object obj)
        {
            Console.Write("In thread pool's thread state:{0}", obj);
            Thread.Sleep(500);
        }

Creating ThreadPool thread using Delegates.

Using the delegate’s BeginInvoke() method will use a thread present in the thread pool. As we know that we can invoke a delegate function using Invoke() and BeginInvoke() methods of the delegate class as discussed here.
The operation of the pointed function can be performed asynchronously using the BeginInvoke() function which inturn uses a thread in the thread pool.

Using Tasks to Create a thread in Thread Pool

Thread pool’s QueueUserWorkItem method is used to initiate asynchrounous compute bound operation and it is very easy to use.
But it has it’s own limitations like there is no way to return the result to the caller or there is no way in which we can get to know that the operation is completed. To address these problems Tasks has been introduced which are present in System.Threading.Tasks namespace.
The below code shows a task in action as compared to a ThreadPool’s QueueUserWorkItem discussed previously

            ThreadPool.QueueUserWorkItem(ThreadPoolOperation, 5);
            new Task(ThreadPoolOperation, 5).Start();

We can return the result from the task operation as shown below

        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(ThreadPoolOperation, 5);
            task.Start();

            int result = task.Result;
            task.Wait();

            Console.WriteLine("In the main thread with result:{0}", result);
            Console.Read();
        }

          private static int ThreadPoolOperation(object obj)
        {            
            Thread.Sleep(1000); // Some long running operation
            return (int)obj * (int)obj;
        }

As shown in the above code the ThreadPoolOperation() method return an integer result after performing some long running operation and the result of this particular task can be retrieved using the Result field of the task instance.

This is all which I wanted to discuss about the ThreadPool in the .NET framework. In this article we have discussed about the scenarios where we need to use the ThreadPool’s thread and the ways in which we can create the threads in a ThreadPool. Please let me know about your thoughts about the article.

 

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview