views:

6432

answers:

8

Looking for some sample code (C#) for a simple thread pool implementation.

I found one on codeproject, but the codebase was just huge and I don't need all that functionality.

This is more for educational purposes anyways.

+2  A: 

Here there is an example:

http://msdn.microsoft.com/en-us/library/3dasc8as.aspx

Carlos Eduardo Olivieri
A: 

A google search led me here, which says:

You can implement your own thread pool, but it is easier to use the thread pool provided by the .NET Framework through the ThreadPool class.

user9876
+12  A: 

There is no need to implement your own, since it is not very hard to use the existing .NET implementation.

From http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx:

using System;
using System.Threading;

public class Fibonacci
{
    public Fibonacci(int n, ManualResetEvent doneEvent)
    {
        _n = n;
        _doneEvent = doneEvent;
    }

    // Wrapper method for use with thread pool.
    public void ThreadPoolCallback(Object threadContext)
    {
        int threadIndex = (int)threadContext;
        Console.WriteLine("thread {0} started...", threadIndex);
        _fibOfN = Calculate(_n);
        Console.WriteLine("thread {0} result calculated...", threadIndex);
        _doneEvent.Set();
    }

    // Recursive method that calculates the Nth Fibonacci number.
    public int Calculate(int n)
    {
        if (n <= 1)
        {
            return n;
        }

        return Calculate(n - 1) + Calculate(n - 2);
    }

    public int N { get { return _n; } }
    private int _n;

    public int FibOfN { get { return _fibOfN; } }
    private int _fibOfN;

    private ManualResetEvent _doneEvent;
}

public class ThreadPoolExample
{
    static void Main()
    {
        const int FibonacciCalculations = 10;

        // One event is used for each Fibonacci object
        ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
        Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
        Random r = new Random();

        // Configure and launch threads using ThreadPool:
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
        for (int i = 0; i < FibonacciCalculations; i++)
        {
            doneEvents[i] = new ManualResetEvent(false);
            Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
            fibArray[i] = f;
            ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
        }

        // Wait for all threads in pool to calculation...
        WaitHandle.WaitAll(doneEvents);
        Console.WriteLine("All calculations are complete.");

        // Display the results...
        for (int i= 0; i<FibonacciCalculations; i++)
        {
            Fibonacci f = fibArray[i];
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
        }
    }
}
Geoffrey Chetwood
let's be smart and answer his question instead.
Henrik
thread pool has huge limitations
Jeffrey C
@Jeffrey: Elaborate.
Geoffrey Chetwood
@Geoffrey: one pool per app domain, can't try abort waiting thread etc. There are heaps of info out therehttp://stackoverflow.com/questions/145304/http://www.codeproject.com/KB/threads/smartthreadpool.aspxhttp://www.codeproject.com/KB/threads/cancellablethreadpool.aspx
Jeffrey C
@Jeffrey: Where are those limitations brought up by the OP? Where in the OP do you see any evidence that the OP needs to roll his own thread pool?
Geoffrey Chetwood
A: 

This ones old but works :)

http://www.codeproject.com/KB/threads/cancellablethreadpool.aspx

It re-creates a ThreadPool instead of implementing a system one (can you do that these days?)

AlSki
+4  A: 

This is the simplest, naive, thread-pool implementation for educational purposes I could come up with (C# / .NET 3.5). It is not using the .NET's thread pool implementation in any way.

using System;
using System.Collections.Generic;
using System.Threading;

namespace SimpleThreadPool
{
 public sealed class Pool : IDisposable
 {
  public Pool(int size)
  {
   this._workers = new LinkedList<Thread>();
   for (var i = 0; i < size; ++i)
   {
    var worker = new Thread(this.Worker) { Name = string.Concat("Worker ", i) };
    worker.Start();
    this._workers.AddLast(worker);
   }
  }

  public void Dispose()
  {
   var waitForThreads = false;
   lock (this._tasks)
   {
    if (!this._disposed)
    {
     GC.SuppressFinalize(this);

     this._disallowAdd = true; // wait for all tasks to finish processing while not allowing any more new tasks
     while (this._tasks.Count > 0)
     {
      Monitor.Wait(this._tasks);
     }

     this._disposed = true;
     Monitor.PulseAll(this._tasks); // wake all workers (none of them will be active at this point; disposed flag will cause then to finish so that we can join them)
     waitForThreads = true;
    }
   }
   if (waitForThreads)
   {
    foreach (var worker in this._workers)
    {
     worker.Join();
    }
   }
  }

  public void QueueTask(Action task)
  {
   lock (this._tasks)
   {
    if (this._disallowAdd) { throw new InvalidOperationException("This Pool instance is in the process of being disposed, can't add anymore"); }
    if (this._disposed) { throw new ObjectDisposedException("This Pool instance has already been disposed"); }
    this._tasks.AddLast(task);
    Monitor.PulseAll(this._tasks); // pulse because tasks count changed
   }
  }

  private void Worker()
  {
   Action task = null;
   while (true)
   {
    lock (this._tasks)
    {
     if (this._disposed)
     {
      return;
     }
     if (null != task)
     {
      this._workers.AddLast(Thread.CurrentThread);
      task = null;
     }
     if (null != this._workers.First && object.ReferenceEquals(Thread.CurrentThread, this._workers.First.Value))
     {
      if (this._tasks.Count > 0)
      {
       task = this._tasks.First.Value;
       this._tasks.RemoveFirst();
       this._workers.RemoveFirst();
       Monitor.PulseAll(this._tasks); // pulse because current (First) worker changed
      }
     }
     if (task == null)
     {
      Monitor.Wait(this._tasks);
      continue;
     }
    }

    task();
   }
  }

  private readonly LinkedList<Thread> _workers;
  private readonly LinkedList<Action> _tasks = new LinkedList<Action>();
  private bool _disallowAdd;
  private bool _disposed;
 }


 public static class Program
 {
  static void Main()
  {
   using (var pool = new Pool(5))
   {
    var random = new Random();
    Action<int> randomizer = (index =>
    {
     Console.WriteLine("{0}: Working on index {1}", Thread.CurrentThread.Name, index);
     Thread.Sleep(random.Next(20, 400));
     Console.WriteLine("{0}: Ending {1}", Thread.CurrentThread.Name, index);
    });

    for (var i = 0; i < 40; ++i)
    {
     var i1 = i;
     pool.QueueTask(() => randomizer(i1));
    }
   }
  }
 }
}
Milan Gardian
A: 

If you're interested in learning more about Threading, you might be interested in this free hands-on training offer from InnerWorkings:

https://www.innerworkings.com/promotions/b47aa369-d35f-4a7c-9fc7-3b452adca696/threading-promotion

+3  A: 

You can use Smart thread pool, I have used in one of my projects , its an open source project from code plex

http://www.codeplex.com/smartthreadpool

Hope this helps

Thanks Shaik

Shaik Phakeer