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() {