title: C# .Is there a .NET class for custom thread pools
body: <p>I have been trying to find a simple custom thread pool for a while, and couldn't find one, so wrote a quick poor man's thread pool. </p>
  
  <p><strong>Questions</strong>: </p>
  
  <ol>
  <li><p>Is there any .NET class that can do this already? (couldn't find it after numerous attempts to find one, only custom implementations on blog posts that were a lot more complex than this!).</p></li>
  <li><p>Better to consume threads with polling or kicking off actions on thread pool when and as tasks come in? &lt;1k tasks / day. This will be running as AspNetCore site on Kestrel</p></li>
  </ol>
  
  <h1>Code</h1>
  
  <pre><code>public class WorkerQueue : IWorkerQueue
  {
      private readonly Queue&lt;WorkItem&gt; _items = new Queue&lt;WorkItem&gt;();
  
      private int _max = 2; // Would be configurable
      private int _running;
      private Stopwatch _stopwatch;
  
      public WorkerQueue()
      {
          _stopwatch = new Stopwatch();
          _stopwatch.Start();
      }
  
      public void Add(WorkItem workItem)
      {
          lock (_items)
          {
              if (_running &gt;= _max)
              {
                  Log($"Queuing Item {workItem.Name} - _running &gt;= _max");
                  _items.Enqueue(workItem);
                  return;
              }
  
              _running++;
  
              Log($"Running Item {workItem.Name} - _running = {_running}");
              var task = Task.Run(workItem.Action);
  
              task.ContinueWith(t =&gt; OnActionCompleted(workItem.Name));
          }
      }
  
      private void Log(string msg)
      {
          Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} @ {_stopwatch.ElapsedMilliseconds}ms : {msg}");
      }
  
      private void OnActionCompleted(string obj)
      {
          Log($"OnActionCompleted {obj}");
          WorkItem item = null;
  
          lock (_items)
          {
              if (_items.Count &gt; 0)
                  item = _items.Dequeue();
              else
                  _running--;
          }
  
          if (item != null)
          {
              // Potential Stack Overflow if big queue builds up?
              // Probably should be a while loop rather than recursion?
              Log($"Running Next Item {item.Name}");
              item.Action();
              OnActionCompleted(item.Name);
          }
          else
          {
              Log($"Sleeping. _running = {_running}");
          }
      }
  }
  </code></pre>
  
  <p>And a test:</p>
  
  <pre><code>    [Fact]
      public void Test()
      {
          var sb = new StringBuilder();
          Console.SetOut(new StringWriter(sb));
  
          var resetEvent = new ManualResetEventSlim();
  
          AddItem("A", 100);
          AddItem("B", 250);
          AddItem("C", 100);
          AddItem("D", 100);
          AddItem("E", 100);
          AddItem("G", 100, () =&gt;
          {
              Thread.Sleep(250);
              resetEvent.Set();
          });
  
          resetEvent.Wait(2500);
  
          Assert.True(resetEvent.IsSet);
  
          _output.WriteLine("");
          _output.WriteLine("------------------ Test Finished ------------------");
          _output.WriteLine("------------------  Console Out  ------------------");
          _output.WriteLine("");
          _output.WriteLine(sb.ToString());
      }
  </code></pre>
  
  <p>And get this output which is correct (or correct enough)</p>
  
  <pre><code>Thread 14 @ 8ms : Running Item A - _running = 1
  Thread 14 @ 8ms : Running Item B - _running = 2
  Thread 14 @ 8ms : Queuing Item C - _running &gt;= _max
  Thread 14 @ 8ms : Queuing Item D - _running &gt;= _max
  Thread 14 @ 8ms : Queuing Item E - _running &gt;= _max
  Thread 14 @ 8ms : Queuing Item G - _running &gt;= _max
  Thread 21 @ 110ms : OnActionCompleted A
  Thread 21 @ 110ms : Running Next Item C
  Thread 21 @ 211ms : OnActionCompleted C
  Thread 21 @ 211ms : Running Next Item D
  Thread 20 @ 260ms : OnActionCompleted B
  Thread 20 @ 260ms : Running Next Item E
  Thread 21 @ 311ms : OnActionCompleted D
  Thread 21 @ 311ms : Running Next Item G
  Thread 20 @ 360ms : OnActionCompleted E
  Thread 20 @ 360ms : Sleeping. _running = 1
  Thread 21 @ 662ms : OnActionCompleted G
  Thread 21 @ 662ms : Sleeping. _running = 0
  </code></pre>