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
}
}