175 lines
3.0 KiB
C#
175 lines
3.0 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Threading;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using System.Linq;
|
|||
|
namespace sharp.extensions
|
|||
|
{
|
|||
|
public delegate void TaskDelegate();
|
|||
|
|
|||
|
public class ExtendableThreadPool
|
|||
|
{
|
|||
|
Stack<ExtendableThread> availableThreads = new Stack<ExtendableThread>();
|
|||
|
List<ExtendableThread> activeThreads = new List<ExtendableThread>();
|
|||
|
|
|||
|
Queue<TaskDelegate> queuedTasks = new Queue<TaskDelegate>();
|
|||
|
|
|||
|
public static ThreadLocal<ExtendableThread> CurrentExtendedThread { get; private set; } = new ThreadLocal<ExtendableThread>();
|
|||
|
|
|||
|
public int MaximumConcurrentThreads { get; set; } = -1;
|
|||
|
|
|||
|
public ExtendableThreadPool()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
public void QueueTask(TaskDelegate task){
|
|||
|
lock(this)
|
|||
|
{
|
|||
|
queuedTasks.Enqueue(task);
|
|||
|
SignalQueue();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SignalQueue(){
|
|||
|
ExtendableThread st;
|
|||
|
|
|||
|
lock (this){
|
|||
|
if (availableThreads.Count > 0){
|
|||
|
st = availableThreads.Pop();
|
|||
|
Monitor.Enter(st);
|
|||
|
Monitor.Pulse(st);
|
|||
|
Monitor.Exit(st);
|
|||
|
} else {
|
|||
|
st = new ExtendableThread(this);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private TaskDelegate fetchTask(){
|
|||
|
lock (this){
|
|||
|
if (queuedTasks.Count == 0){
|
|||
|
return null;
|
|||
|
} else {
|
|||
|
return queuedTasks.Dequeue();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected void InvokeTaskDelegate(TaskDelegate task)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
task.Invoke();
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
Console.WriteLine("InvokeTaskDelegate:t Task threw exception: {0}", e.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class ExtendableThread
|
|||
|
{
|
|||
|
Thread thread;
|
|||
|
bool requestExit;
|
|||
|
bool isReady;
|
|||
|
|
|||
|
public ExtendableThreadPool Pool { get; private set; }
|
|||
|
|
|||
|
public ExtendableThread(ExtendableThreadPool pool)
|
|||
|
{
|
|||
|
Pool = pool;
|
|||
|
thread = new Thread(worker);
|
|||
|
thread.Start();
|
|||
|
}
|
|||
|
|
|||
|
public bool IsReady {
|
|||
|
get
|
|||
|
{
|
|||
|
lock (this){
|
|||
|
return isReady;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool ExitRequested {
|
|||
|
get { lock(this) { return requestExit; } }
|
|||
|
}
|
|||
|
|
|||
|
protected void InvokeTaskDelegate(TaskDelegate task)
|
|||
|
{
|
|||
|
Pool.InvokeTaskDelegate(task);
|
|||
|
}
|
|||
|
|
|||
|
private void worker(){
|
|||
|
ExtendableThreadPool.CurrentExtendedThread.Value = this;
|
|||
|
|
|||
|
bool taskAvailable = true;
|
|||
|
|
|||
|
while (!ExitRequested){
|
|||
|
TaskDelegate t;
|
|||
|
|
|||
|
while ((t = Pool.fetchTask()) != null)
|
|||
|
{
|
|||
|
if (t != null)
|
|||
|
{
|
|||
|
InvokeTaskDelegate(t);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
lock(Pool)
|
|||
|
{
|
|||
|
Pool.activeThreads.Remove(this);
|
|||
|
Pool.availableThreads.Push(this);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
lock(this)
|
|||
|
{
|
|||
|
isReady = true;
|
|||
|
|
|||
|
while (!Monitor.Wait(this, 250) && !ExitRequested) { }
|
|||
|
|
|||
|
if (ExitRequested)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
lock (Pool)
|
|||
|
{
|
|||
|
Pool.activeThreads.Add(this);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
lock(this){
|
|||
|
Monitor.Pulse(this);
|
|||
|
isReady = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Stop()
|
|||
|
{
|
|||
|
lock (this)
|
|||
|
{
|
|||
|
requestExit = true;
|
|||
|
}
|
|||
|
}
|
|||
|
public void Stop(int timeoutms)
|
|||
|
{
|
|||
|
lock (this)
|
|||
|
{
|
|||
|
requestExit = true;
|
|||
|
Monitor.Wait(this, timeoutms);
|
|||
|
if (thread.IsAlive){
|
|||
|
thread.Abort();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
}
|