using System.Threading; using System.Collections; using AsterNET.FastAGI; using System.Collections.Generic; namespace AsterNET.Util { /// /// A fixed sized thread pool. /// public class ThreadPool { #if LOGGER private Logger logger = Logger.Instance(); #endif private bool running; private int numThreads; private string name; private List jobs; #region Constructor - ThreadPool(string name, int numThreads) /// /// Creates a new ThreadPool of numThreads size. These Threads are waiting /// for jobs to be added via the addJob method. /// /// the name to use for the thread group and worker threads. /// the number of threads to create. public ThreadPool(string name, int numThreads) { this.name = name; this.numThreads = numThreads; jobs = new List(); running = true; // create and start the threads for (int i = 0; i < this.numThreads; i++) { ThreadTask thread; thread = new ThreadTask(this, this.name + "-TaskThread-" + i); thread.Start(); } #if LOGGER logger.Debug("ThreadPool created with " + this.numThreads + " threads."); #endif } #endregion #region obtainJob() /// /// Gets a job from the queue. If none is availble the calling thread is /// blocked until one is added. /// /// the next job to service, null if the worker thread should be shut down. internal AGIConnectionHandler obtainJob() { AGIConnectionHandler job = null; lock (jobs) { while (job == null && running) { try { if (jobs.Count == 0) Monitor.Wait(jobs); } catch (ThreadInterruptedException ex) { #if LOGGER logger.Error("System.Threading.ThreadInterruptedException.", ex); #else throw ex; #endif } if (jobs.Count > 0) { job = jobs[0]; jobs.RemoveAt(0); } } } if (running) return job; else return null; } #endregion #region AddJob(AGIConnectionHandler runnable) /// Adds a new job to the queue. This will be picked up by the next available /// active thread. /// public void AddJob(AGIConnectionHandler runnable) { lock (jobs) { jobs.Add(runnable); Monitor.PulseAll(jobs); } } #endregion #region Shutdown() /// Turn off the pool. Every thread, when finished with its current work, /// will realize that the pool is no longer running, and will exit. /// public void Shutdown() { running = false; lock (jobs) Monitor.PulseAll(jobs); #if LOGGER logger.Debug("ThreadPool shutting down."); #endif } #endregion } }