# HG changeset patch # User cin # Date 2013-11-05 15:55:34 # Node ID eb418ba8275b82bd1ab6fa2736cd06a6ace539fb # Parent 6ec82bf68c8ef041e506358eacf67fee6f77263e refactoring, added WorkerPool diff --git a/Implab.suo b/Implab.suo index fe568ef8e83a685430ea861c1a089f2705ea5f4b..39be6a30b2af76bbf8a5b2d784ab6eedfd7ed4db GIT binary patch literal 48128 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 ax$l9FU(WlRzw_C~AO7W;20KwTXZU|?4$f%+ diff --git a/Implab/ICancellable.cs b/Implab/ICancellable.cs new file mode 100644 --- /dev/null +++ b/Implab/ICancellable.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Implab { + public interface ICancellable { + bool Cancel(); + } +} diff --git a/Implab/IProgressHandler.cs b/Implab/IProgressHandler.cs new file mode 100644 --- /dev/null +++ b/Implab/IProgressHandler.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Implab { + public interface IProgressHandler { + string Message { + get; + set; + } + float CurrentProgress { + get; + set; + } + void InitProgress(float current, float max, string message); + } +} diff --git a/Implab/IProgressNotifier.cs b/Implab/IProgressNotifier.cs new file mode 100644 --- /dev/null +++ b/Implab/IProgressNotifier.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Implab +{ + public interface IProgressNotifier + { + event EventHandler> MessageUpdated; + event EventHandler> ProgressUpdated; + EventHandler ProgressInit; + } +} diff --git a/Implab/IPromise.cs b/Implab/IPromise.cs --- a/Implab/IPromise.cs +++ b/Implab/IPromise.cs @@ -5,7 +5,7 @@ using System.Text; namespace Implab { - public interface IPromise + public interface IPromise: ICancellable { /// /// Check whereather the promise has no more than one dependent promise. @@ -24,12 +24,6 @@ namespace Implab } /// - /// Tries to cancel the the complete chain of promises. - /// - /// true - if the promise has been cancelled, otherwise the promise will be resolved (or resolved already). - bool Cancel(); - - /// /// Registers handler for the case when the promise is cencelled. If the promise already cancelled the /// handler will be invoked immediatelly. /// diff --git a/Implab/ITaskController.cs b/Implab/ITaskController.cs new file mode 100644 --- /dev/null +++ b/Implab/ITaskController.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Implab { + public interface ITaskController: IProgressHandler { + bool Cancelled { + get; + } + } +} diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj --- a/Implab/Implab.csproj +++ b/Implab/Implab.csproj @@ -32,7 +32,13 @@ + + + + + + diff --git a/Implab/ManagedPromise.cs b/Implab/ManagedPromise.cs new file mode 100644 --- /dev/null +++ b/Implab/ManagedPromise.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Implab { + + public class ManagedPromise: Promise, ITaskController, IProgressNotifier { + + } +} diff --git a/Implab/Parallels/WorkerPool.cs b/Implab/Parallels/WorkerPool.cs new file mode 100644 --- /dev/null +++ b/Implab/Parallels/WorkerPool.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Diagnostics; + +namespace Implab.Parallels { + public class WorkerPool : IDisposable { + readonly int m_minThreads; + readonly int m_maxThreads; + int m_runningThreads; + object m_lock = new object(); + + bool m_disposed = false; + ManualResetEvent m_hasTasks = new ManualResetEvent(false); + Queue m_queue = new Queue(); + + public WorkerPool(int min, int max) { + if (min < 0) + throw new ArgumentOutOfRangeException("min"); + if (min > max) + min = max; + m_minThreads = min; + m_maxThreads = max; + + for (int i = 0; i < m_minThreads; i++) + StartWorker(); + } + + public Promise Invoke(Func task) { + if (m_disposed) + throw new ObjectDisposedException(ToString()); + if (task == null) + throw new ArgumentNullException("task"); + + var promise = new Promise(); + + + + return promise; + } + + bool StartWorker() { + var current = m_runningThreads; + // use spins to allocate slot for the new thread + do { + if (current >= m_maxThreads) + // no more slots left + return false; + } while (current != Interlocked.CompareExchange(ref m_runningThreads, current + 1, current)); + + // slot successfully allocated + + var worker = new Thread(this.Worker); + worker.Start(); + + return true; + } + + void EnqueueTask(Action task) { + Debug.Assert(task != null); + lock (m_queue) { + m_queue.Enqueue(task); + m_hasTasks.Set(); + } + } + + bool FetchTask(out Action task) { + task = null; + + while (true) { + + m_hasTasks.WaitOne(); + + if (m_disposed) + return false; + + lock (m_queue) { + if (m_queue.Count > 0) { + task = m_queue.Dequeue(); + return true; + } + + // no tasks left + // signal that no more tasks left, lock ensures that this event won't suppress newly added task + m_hasTasks.Reset(); + } + + bool exit = true; + + var current = m_runningThreads; + do { + if (current <= m_minThreads) { + exit = false; // this thread should return and wait for the new events + break; + } + } while (current != Interlocked.CompareExchange(ref m_runningThreads, current - 1, current)); + + if (exit) + return false; + } + } + + void Worker() { + Action task; + while (FetchTask(out task)) + task(); + } + + protected virtual void Dispose(bool disposing) { + if (disposing) { + lock (m_lock) { + if (m_disposed) + return; + m_disposed = true; + } + m_hasTasks.Set(); + GC.SuppressFinalize(this); + } + } + + public void Dispose() { + Dispose(true); + } + + ~WorkerPool() { + Dispose(false); + } + } +} diff --git a/Implab/ProgressInitEventArgs.cs b/Implab/ProgressInitEventArgs.cs --- a/Implab/ProgressInitEventArgs.cs +++ b/Implab/ProgressInitEventArgs.cs @@ -5,7 +5,7 @@ using System.Text; namespace Implab { - + [Serializable] public class ProgressInitEventArgs: EventArgs { public float MaxProgress diff --git a/Implab/TaskController.cs b/Implab/TaskController.cs --- a/Implab/TaskController.cs +++ b/Implab/TaskController.cs @@ -12,7 +12,7 @@ namespace Implab /// /// Members of this object are thread safe. /// - class TaskController + class TaskController: IProgressNotifier, ITaskController, ICancellable { readonly object m_lock; string m_message; @@ -20,6 +20,8 @@ namespace Implab float m_current; float m_max; + bool m_cancelled; + public event EventHandler> MessageUpdated; public event EventHandler> ProgressUpdated; public event EventHandler ProgressInit; @@ -82,6 +84,24 @@ namespace Implab } } + public bool Cancelled { + get { + lock (m_lock) + return m_cancelled; + } + } + + public bool Cancel() { + lock (m_lock) { + if (!m_cancelled) { + m_cancelled = true; + return true; + } else { + return false; + } + } + } + protected virtual void OnMessageUpdated() { var temp = MessageUpdated; diff --git a/Implab/ValueEventArgs.cs b/Implab/ValueEventArgs.cs --- a/Implab/ValueEventArgs.cs +++ b/Implab/ValueEventArgs.cs @@ -5,6 +5,7 @@ using System.Text; namespace Implab { + [Serializable] public class ValueEventArgs: EventArgs { public ValueEventArgs(T value)