The series so far:

  1. The Unconventional Guide to Introduction to Thread
  2. Why Do People Think Dedicated CLR Threads is a Good Idea?
  3. How Not Knowing Thread Members and Execution State Makes You a Rookie
  4. Doing Thread Scheduling and Priority the Right Way
  5. How to Start Using CLR's Thread Pool
  6. What Wikipedia Can't Tell You About Thread Execution Contexts
  7. The Insider's Guide to Cooperative Cancellation and Timeout

Introduction

Thread pool is a set of threads that are available for your application’s use.

  1. CLR contains code to manage own Thread Pool
  2. One Thread Pool per CLR and shared by all AppDomains

Threadpooling--1-

Note: Threadpool threads are background by default

Working of Threadpool Threads

  1. As tasks arrive they are placed on a queue.
  2. Threads on the Threadpool grab the next available task on the queue.

Threadpool-Tasks

Threadpool thread kiling spree

When a threadpool thread has been idle with nothing to do for some period of time, the thread wakes itself up and kill itself to free up resources.

  1. Time to kill after idle depends on CLR.
  2. As the thread is killing itself, there is a performance hit.
  3. However, this probably doesn’t matter, because the thread is killing itself, because it has been idle, which means that your application isn’t performing a lot of work.

Managing Worker Threads

  1. Global Queue is used to manage the items with FIFO
  2. If Worker threads enqueue work items they have their local queue for that and have access to head only LIFO. Hence Reversed execution.
  3. Steal from other Local Queue, if local empty
  4. Finally from Global Queue, if all empty
  5. If Global Empty, Sleep Waiting
  6. If Sleep Waiting for long, kills it

Worker-Threads--1-

Note: Windows Scheduler determines which thread to schedule first

Demo

Performing a simple Compute-Bound Operation using Thread Pool. Please found the running version here.

//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

// Threading namespace
using System.Threading;

namespace Rextester {
  public class Program {
    public static void Main(string[] args) {
      //Your code goes here
      Console.WriteLine("Hello, world!");
      DoWork();
    }

    public static void DoWork() {
      // Queue a task.  
      System.Threading.ThreadPool.QueueUserWorkItem(
        new System.Threading.WaitCallback(SomeLongTask));
      // Queue another task.  
      System.Threading.ThreadPool.QueueUserWorkItem(
        new System.Threading.WaitCallback(AnotherLongTask));
      System.Threading.Thread.Sleep(5000);
    }

    private static void SomeLongTask(Object state) {
      Console.WriteLine("Long Task picked up by " + Thread.CurrentThread.ManagedThreadId);
      // Insert code to perform a long task.  
      Console.WriteLine("Long Task Started");
      System.Threading.Thread.Sleep(1000);
      Console.WriteLine("Long Task Ended");
    }

    private static void AnotherLongTask(Object state) {
      Console.WriteLine("Another Long Task picked up by " + Thread.CurrentThread.ManagedThreadId);
      // Insert code to perform a long task.  
      Console.WriteLine("Another Long Task Started");
      System.Threading.Thread.Sleep(500);
      Console.WriteLine("Another Long Task Ended");
    }
  }
}