jellyfin-server/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs

167 lines
3.3 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.Abort ();
} 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 ();
}
}
}