diff --git a/Source/Scheduling/Operation.cs b/Source/Scheduling/Operation.cs index 112cfb7..ce66dac 100644 --- a/Source/Scheduling/Operation.cs +++ b/Source/Scheduling/Operation.cs @@ -27,8 +27,57 @@ namespace Nuclex.Support.Scheduling { /// Base class for observable operations running in the background public abstract class Operation : Progression { + /// Executes the operation synchronously + public virtual void Execute() { + Begin(); + End(); + } + /// Launches the background operation - public abstract void Start(); + public abstract void Begin(); + + /// Waits for the background operation to end + /// + /// Any exceptions raised in the background operation will be thrown + /// in this method. + /// + public virtual void End() { + + // Use some ingenious double-checked locking to set the endCalled flag. + // Quite a lot of effort for a mere safety feature that prevents the programmer + // from calling End() twice. + bool error; + if(!this.endCalled) { + lock(this) { + if(!this.endCalled) { + this.endCalled = true; + error = false; + } else { + error = true; + } + } + } else { + error = true; + } + + // If the progression itself hasn't ended yet, block the caller until it has. + if(!Ended) + WaitHandle.WaitOne(); + + // If an exception occured during the background execution + if(this.occuredException != null) + throw this.occuredException; + + } + + /// Exception that occured while the operation was executing + /// + /// If this field is null, it is assumed that no exception has occured + /// in the background process. When it is set, the End() method will + /// + protected Exception occuredException; + /// Whether the End() method has been called already + private volatile bool endCalled; } diff --git a/Source/Scheduling/ThreadedMethodOperation.cs b/Source/Scheduling/ThreadedMethodOperation.cs index 52b4f16..8f1466d 100644 --- a/Source/Scheduling/ThreadedMethodOperation.cs +++ b/Source/Scheduling/ThreadedMethodOperation.cs @@ -19,10 +19,62 @@ License along with this library #endregion using System; using System.Collections.Generic; +using System.Threading; namespace Nuclex.Support.Scheduling { -/* + + /// Operation that executes a method in a background thread public class ThreadedMethodOperation : Operation { + + /// + /// Initializes a new threaded method operation for a parameterless method + /// + /// Method to be invoked in a background thread + /// + /// Uses a ThreadPool thread to execute the method in + /// + public ThreadedMethodOperation(ThreadStart method) + : this(method, true) { } + + /// + /// Initializes a new threaded method operation for a parameterless method + /// + /// Method to be invoked in a background thread + /// Whether to use a ThreadPool thread + /// + /// If useThreadPool is false, a new thread will be created. This guarantees + /// that the method will be executed immediately but has an impact on + /// performance since the creation of new threads is not a cheap operation. + /// + public ThreadedMethodOperation(ThreadStart method, bool useThreadPool) { + if(useThreadPool) { + ThreadPool.QueueUserWorkItem(callMethod, method); + } else { + Thread thread = new Thread(callMethod); + thread.Name = "Nuclex.Support.Scheduling.ThreadedMethodOperation thread"; + thread.IsBackground = true; + thread.Start(method); + } + } + + /// Invokes the delegate passed as an argument + /// ThreadStart-comaptible Delegate to invoke + private void callMethod(object method) { +#if PROGRESSION_STARTABLE + AsyncStarted(); +#endif + + try { + ((ThreadStart)method)(); + } + catch(Exception exception) { + this.occuredException = exception; + } + finally { + AsyncEnded(); + } + } + } -*/ + } // namespace Nuclex.Support.Scheduling diff --git a/Source/Tracking/SetProgression.cs b/Source/Tracking/SetProgression.cs index e7053d6..a5e3c85 100644 --- a/Source/Tracking/SetProgression.cs +++ b/Source/Tracking/SetProgression.cs @@ -69,7 +69,6 @@ namespace Nuclex.Support.Tracking { : this() { // Construct an ObservedProgression around each of the WeightedProgressions - float totalWeight = 0.0f; foreach(WeightedProgression progression in childs) { this.childs.Add( new ObservedProgression( @@ -80,12 +79,9 @@ namespace Nuclex.Support.Tracking { ); // Sum up the total weight - totalWeight += progression.Weight; + this.totalWeight += progression.Weight; } - // Take over the summed weight of all progressions we were given - this.totalWeight = totalWeight; - } /// Immediately releases all resources owned by the object @@ -150,7 +146,7 @@ namespace Nuclex.Support.Tracking { } /// - /// Called when an observed progressions ends + /// Called when an observed progression ends /// private void asyncEnded() {