Friday, September 30, 2011

Working with Thread Pool in C# (Dotnet)


What is Thread Pool?

Thread pool is collection of Threads which can be used to perform different tasks in background. All threads available in Thread Pool can be used as Background ThreadBackground thread runs asynchronously in background and remains main thread active (UI will be responsive). When you create and start Thread it takes some significant time to create it in memory, instead Thread pool can be used. Thread pool manages overhead to create and recycle threads. Thread pool keeps watch on total number of worker threads are running asynchronously if it reached to its limit then threads are queued up and wait until any of the thread finishes its task from Thread pool. This way thread pool reuses the threads and avoids the cost of creating new threads each time. We can explicitly set Max and Min limit of Threads that Thread Pool creates by calling ThreadPool.SetMaxThread and ThreadPool.SetMinThread methods respectively.


How to work with Thread Pool?

There are number of ways to use thread pool in your application.

1.       ThreadPool.QueueUserWorkItem
2.       Task Parallel Library (PLINQ)
3.       Delegates (asynchronous delegates)
4.       BackgroundWorker


ThreadPool.QueueUserWorkItem

Thread pool class provides facility to queue items using QueueUserWorkItem method. This method accepts WaitCallBack delegate. Let’s have a look on below code.

public static void Main()
{
    Console.WriteLine("Calling from Main Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());

    ThreadPool.QueueUserWorkItem(DoSomething);
}

private static void DoSomething(object x)
{
    Console.WriteLine("Calling from Thread Pool's Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());
    Console.WriteLine("Hi, I am using Thread Pool");
}

Output
Calling from Main Thread...
Is Thread Pool Thread : False
Calling from Thread Pool's Thread...
Is Thread Pool Thread : True
Hi, I am using Thread Pool

In above code, I have used ThreadPool.QueueUserWorkItem method to request queue for my task from Thread pool. This methods queue thread requested and allocate thread from thread pool class if available. This method accepts WaitCallBack delegate and as per delegate signature it accepts one argument of object type so I have added one argument to DoSomething method. In above code I have not passed any argument to DoSomething method so it will take null as default. Another interesting thing is you can check whether the thread is from Thread pool or not using Thread.CurrentThread.IsThreadPoolThread. This property returns true if the thread is from Thread pool and returns false if not.


Task Parallel Library (PLINQ)

Task Parallel Library is introduced with Dotnet Framework 4.0. We can use Task class of TPL to enter into Thread Pool. Task class provides Factory to start new task from Thread pool. Let’s have a look on below code.

public static void Main()
{
    Console.WriteLine("Calling from Main Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());

    Task.Factory.StartNew(DoSomething);
}

private static void DoSomething()
{
    Console.WriteLine("Calling from Thread Pool's Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());
    Console.WriteLine("Hi, I am using Thread Pool");
}

Output
Calling from Main Thread...
Is Thread Pool Thread : False
Calling from Thread Pool's Thread...
Is Thread Pool Thread : True
Hi, I am using Thread Pool

In above code, Task class used to start new thread from Thread pool. Task.Factory.StartNew method used to start thread from thread pool. StartNew method accepts delegate action as parameter.


Asynchronous Delegate

Asynchronous delegate internally uses thread from Thread Pool class. You can pass arguments and return value from delegate method. Let’s have a look on below code.

public static void Main()
{
    Console.WriteLine("Calling from Main Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());

    Func<string, int> MyDelegate = DoSomething;
    MyDelegate.BeginInvoke("Hello", null, null);
}

private static int DoSomething(string x)
{
    Console.WriteLine("Calling from Thread Pool's Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());
    Console.WriteLine("Hi, I am using Thread Pool");
    return 0;
}

Output
Calling from Main Thread...
Is Thread Pool Thread : False
Calling from Thread Pool's Thread...
Is Thread Pool Thread : True
Hi, I am using Thread Pool

In above example, I made few changes in existing example and used asynchronous delegate. When you call BeginInvoke method of delegate it executes task in parallel thread and the thread will be pooled from ThreadPool class. I have created one Func<> delegate with string argument and integer as return type. This method is being executed in background thread of Thread pool class.


BackgroundWorker

Background worker class also uses thread from Thread pool to perform task in background. For more information about background worker you can go through my post on BackgroundWorker. Let’s have a look on below code
.
BackgroundWorker workerThread;

public static void Main()
{
    workerThread = new BackgroundWorker();
    workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
    workerThread.RunWorkerCompleted += new
        RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);

    Console.WriteLine("Calling from Main Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());
    workerThread.RunWorkerAsync();  
}
private void workerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Console.WriteLine("Worker thread completed.");
}

private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
    Console.WriteLine("Calling from Thread Pool's Thread...");
    Console.WriteLine("Is Thread Pool Thread : " +
        Thread.CurrentThread.IsThreadPoolThread.ToString());
    Console.WriteLine("Hi, I am using Thread Pool");
}

Output
Calling from Main Thread...
Is Thread Pool Thread : False
Calling from Thread Pool's Thread...
Is Thread Pool Thread : True
Hi, I am using Thread Pool
Worker thread completed.

As per above code, I have created one instance of BackgroundWorker class. I have also attached DoWork and RunWorkerCompleted methods to backgroundworker instance. So when I call RunWorkerAsync method of worker thread it will be executed on separate thread in background and thread will be pooled form Thread pool. When worker thread completes it will notify user with completed state.

As explained above, these all are the ways to use threads from Thread pool.

Hope you liked this post. Please leave your comments and feedback in comments section of this post.

See also –

4 comments:

  1. The "DoSomething(string x)" Method should be Static. Member methods can not be assigned to Func.

    ReplyDelete
  2. Hi Shivshankar, You are correct, 'DoSomething' method should be static. I created non console application and copied to blog directly so forgot make DoSomething method as static. Thanks for pointing out mistake.

    ReplyDelete