184 lines
4.7 KiB
C#
184 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using ST = System.Threading;
|
|
|
|
namespace SharpCifs.Util.Sharpen
|
|
{
|
|
class ThreadPoolExecutor
|
|
{
|
|
ThreadFactory _tf;
|
|
int _corePoolSize;
|
|
int _maxPoolSize;
|
|
List<Thread> _pool = new List<Thread>();
|
|
int _runningThreads;
|
|
int _freeThreads;
|
|
bool _shutdown;
|
|
Queue<IRunnable> _pendingTasks = new Queue<IRunnable>();
|
|
|
|
public ThreadPoolExecutor(int corePoolSize, ThreadFactory factory)
|
|
{
|
|
this._corePoolSize = corePoolSize;
|
|
_maxPoolSize = corePoolSize;
|
|
_tf = factory;
|
|
}
|
|
|
|
public void SetMaximumPoolSize(int size)
|
|
{
|
|
_maxPoolSize = size;
|
|
}
|
|
|
|
public bool IsShutdown()
|
|
{
|
|
return _shutdown;
|
|
}
|
|
|
|
public virtual bool IsTerminated()
|
|
{
|
|
lock (_pendingTasks)
|
|
{
|
|
return _shutdown && _pendingTasks.Count == 0;
|
|
}
|
|
}
|
|
|
|
public virtual bool IsTerminating()
|
|
{
|
|
lock (_pendingTasks)
|
|
{
|
|
return _shutdown && !IsTerminated();
|
|
}
|
|
}
|
|
|
|
public int GetCorePoolSize()
|
|
{
|
|
return _corePoolSize;
|
|
}
|
|
|
|
public void PrestartAllCoreThreads()
|
|
{
|
|
lock (_pendingTasks)
|
|
{
|
|
while (_runningThreads < _corePoolSize)
|
|
StartPoolThread();
|
|
}
|
|
}
|
|
|
|
public void SetThreadFactory(ThreadFactory f)
|
|
{
|
|
_tf = f;
|
|
}
|
|
|
|
public void Execute(IRunnable r)
|
|
{
|
|
InternalExecute(r, true);
|
|
}
|
|
|
|
internal void InternalExecute(IRunnable r, bool checkShutdown)
|
|
{
|
|
lock (_pendingTasks)
|
|
{
|
|
if (_shutdown && checkShutdown)
|
|
throw new InvalidOperationException();
|
|
if (_runningThreads < _corePoolSize)
|
|
{
|
|
StartPoolThread();
|
|
}
|
|
else if (_freeThreads > 0)
|
|
{
|
|
_freeThreads--;
|
|
}
|
|
else if (_runningThreads < _maxPoolSize)
|
|
{
|
|
StartPoolThread();
|
|
}
|
|
_pendingTasks.Enqueue(r);
|
|
ST.Monitor.PulseAll(_pendingTasks);
|
|
}
|
|
}
|
|
|
|
void StartPoolThread()
|
|
{
|
|
_runningThreads++;
|
|
_pool.Add(_tf.NewThread(new RunnableAction(RunPoolThread)));
|
|
}
|
|
|
|
public void RunPoolThread()
|
|
{
|
|
while (!IsTerminated())
|
|
{
|
|
try
|
|
{
|
|
IRunnable r = null;
|
|
lock (_pendingTasks)
|
|
{
|
|
_freeThreads++;
|
|
while (!IsTerminated() && _pendingTasks.Count == 0)
|
|
ST.Monitor.Wait(_pendingTasks);
|
|
if (IsTerminated())
|
|
break;
|
|
r = _pendingTasks.Dequeue();
|
|
}
|
|
if (r != null)
|
|
r.Run();
|
|
}
|
|
//supress all errors, anyway
|
|
//catch (ST.ThreadAbortException) {
|
|
// // Do not catch a thread abort. If we've been aborted just let the thread die.
|
|
// // Currently reseting an abort which was issued because the appdomain is being
|
|
// // torn down results in the process living forever and consuming 100% cpu time.
|
|
// return;
|
|
//}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void Shutdown()
|
|
{
|
|
lock (_pendingTasks)
|
|
{
|
|
_shutdown = true;
|
|
ST.Monitor.PulseAll(_pendingTasks);
|
|
}
|
|
}
|
|
|
|
public virtual List<IRunnable> ShutdownNow()
|
|
{
|
|
lock (_pendingTasks)
|
|
{
|
|
_shutdown = true;
|
|
foreach (var t in _pool)
|
|
{
|
|
try
|
|
{
|
|
t.Cancel(true);
|
|
t.Dispose();
|
|
}
|
|
catch { }
|
|
}
|
|
_pool.Clear();
|
|
_freeThreads = 0;
|
|
_runningThreads = 0;
|
|
var res = new List<IRunnable>(_pendingTasks);
|
|
_pendingTasks.Clear();
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
|
|
class RunnableAction : IRunnable
|
|
{
|
|
Action _action;
|
|
|
|
public RunnableAction(Action a)
|
|
{
|
|
_action = a;
|
|
}
|
|
|
|
public void Run()
|
|
{
|
|
_action();
|
|
}
|
|
}
|
|
}
|