Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs	(revision 15407)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs	(revision 15408)
@@ -47,11 +47,14 @@
       this.tabControl = new HeuristicLab.MainForm.WindowsForms.DragOverTabControl();
       this.optimizersTabPage = new System.Windows.Forms.TabPage();
+      this.experimentTreeView = new HeuristicLab.Optimization.Views.ExperimentTreeView();
       this.runsTabPage = new System.Windows.Forms.TabPage();
       this.runsViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
-      this.experimentTreeView = new HeuristicLab.Optimization.Views.ExperimentTreeView();
+      this.workersNumericUpDown = new System.Windows.Forms.NumericUpDown();
+      this.workersLabel = new System.Windows.Forms.Label();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.tabControl.SuspendLayout();
       this.optimizersTabPage.SuspendLayout();
       this.runsTabPage.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.workersNumericUpDown)).BeginInit();
       this.SuspendLayout();
       // 
@@ -119,4 +122,15 @@
       this.optimizersTabPage.Text = "Optimizers";
       this.optimizersTabPage.UseVisualStyleBackColor = true;
+      // 
+      // experimentTreeView
+      // 
+      this.experimentTreeView.Caption = "Experiment View";
+      this.experimentTreeView.Content = null;
+      this.experimentTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.experimentTreeView.Location = new System.Drawing.Point(3, 3);
+      this.experimentTreeView.Name = "experimentTreeView";
+      this.experimentTreeView.ReadOnly = false;
+      this.experimentTreeView.Size = new System.Drawing.Size(665, 395);
+      this.experimentTreeView.TabIndex = 0;
       // 
       // runsTabPage
@@ -147,19 +161,38 @@
       this.runsViewHost.ViewType = null;
       // 
-      // experimentTreeView
-      // 
-      this.experimentTreeView.Caption = "Experiment View";
-      this.experimentTreeView.Content = null;
-      this.experimentTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.experimentTreeView.Location = new System.Drawing.Point(3, 3);
-      this.experimentTreeView.Name = "experimentTreeView";
-      this.experimentTreeView.ReadOnly = false;
-      this.experimentTreeView.Size = new System.Drawing.Size(665, 395);
-      this.experimentTreeView.TabIndex = 0;
+      // workersNumericUpDown
+      // 
+      this.workersNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.workersNumericUpDown.Location = new System.Drawing.Point(193, 461);
+      this.workersNumericUpDown.Minimum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+      this.workersNumericUpDown.Name = "workersNumericUpDown";
+      this.workersNumericUpDown.Size = new System.Drawing.Size(59, 20);
+      this.workersNumericUpDown.TabIndex = 16;
+      this.workersNumericUpDown.Value = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+      this.workersNumericUpDown.ValueChanged += new System.EventHandler(this.workersNumericUpDown_ValueChanged);
+      // 
+      // workersLabel
+      // 
+      this.workersLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.workersLabel.AutoSize = true;
+      this.workersLabel.Location = new System.Drawing.Point(140, 464);
+      this.workersLabel.Name = "workersLabel";
+      this.workersLabel.Size = new System.Drawing.Size(53, 13);
+      this.workersLabel.TabIndex = 17;
+      this.workersLabel.Text = "Workers: ";
       // 
       // ExperimentView
       // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.workersLabel);
+      this.Controls.Add(this.workersNumericUpDown);
       this.Controls.Add(this.tabControl);
       this.Name = "ExperimentView";
@@ -175,8 +208,11 @@
       this.Controls.SetChildIndex(this.nameLabel, 0);
       this.Controls.SetChildIndex(this.nameTextBox, 0);
+      this.Controls.SetChildIndex(this.workersNumericUpDown, 0);
+      this.Controls.SetChildIndex(this.workersLabel, 0);
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
       this.tabControl.ResumeLayout(false);
       this.optimizersTabPage.ResumeLayout(false);
       this.runsTabPage.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.workersNumericUpDown)).EndInit();
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -190,5 +226,6 @@
     private HeuristicLab.MainForm.WindowsForms.ViewHost runsViewHost;
     private ExperimentTreeView experimentTreeView;
-
+    private System.Windows.Forms.NumericUpDown workersNumericUpDown;
+    private System.Windows.Forms.Label workersLabel;
   }
 }
Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs	(revision 15407)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs	(revision 15408)
@@ -20,4 +20,5 @@
 #endregion
 
+using System;
 using System.Linq;
 using System.Windows.Forms;
@@ -43,7 +44,9 @@
         experimentTreeView.Content = null;
         runsViewHost.Content = null;
+        workersNumericUpDown.Value = 1;
       } else {
         experimentTreeView.Content = Content;
         runsViewHost.Content = Content.Runs;
+        workersNumericUpDown.Value = Content.NumberOfWorkers;
       }
     }
@@ -66,4 +69,15 @@
       base.OnClosed(e);
     }
+
+    protected override void Content_ExecutionStateChanged(object sender, EventArgs e) {
+      base.Content_ExecutionStateChanged(sender, e);
+      workersNumericUpDown.Enabled = Content.ExecutionState != ExecutionState.Started;
+    }
+
+    #region Events
+    private void workersNumericUpDown_ValueChanged(object sender, System.EventArgs e) {
+      Content.NumberOfWorkers = (int)workersNumericUpDown.Value;
+    }
+    #endregion
   }
 }
Index: /trunk/sources/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 15407)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 15408)
@@ -80,11 +80,8 @@
       try {
         Run((object)cancellationTokenSource.Token);
-      }
-      catch (OperationCanceledException) {
-      }
-      catch (AggregateException ae) {
+      } catch (OperationCanceledException) {
+      } catch (AggregateException ae) {
         ae.FlattenAndHandle(new[] { typeof(OperationCanceledException) }, e => OnExceptionOccurred(e));
-      }
-      catch (Exception e) {
+      } catch (Exception e) {
         OnExceptionOccurred(e);
       }
@@ -104,5 +101,5 @@
       base.Pause();
       pausePending = true;
-      CancellationTokenSource.Cancel();
+      CancellationTokenSource?.Cancel();
     }
 
@@ -112,5 +109,5 @@
       base.Stop();
       if (ExecutionState == ExecutionState.Paused) OnStopped();
-      else CancellationTokenSource.Cancel();
+      else CancellationTokenSource?.Cancel();
     }
 
@@ -127,6 +124,5 @@
         initialized = true;
         Run(cancellationToken);
-      }
-      finally {
+      } finally {
         timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
         timer.Stop();
Index: /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 15407)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 15408)
@@ -258,4 +258,5 @@
         if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
         Optimizer.Prepare();
+        if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
       }
     }
@@ -271,5 +272,5 @@
       if (Optimizer.ExecutionState != ExecutionState.Started) return;
       // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-      try { Optimizer.Pause(); } catch (InvalidOperationException) { }
+      try { Optimizer.Pause(); } catch (InvalidOperationException) { } catch (NotSupportedException) { }
     }
     public void Stop() {
Index: /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 15407)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 15408)
@@ -97,4 +97,14 @@
     }
 
+    [Storable]
+    private int numberOfWorkers = 1;
+    public int NumberOfWorkers {
+      get { return numberOfWorkers; }
+      set {
+        if (value < 1) throw new ArgumentException("Number of Workers must not be lower than one.");
+        numberOfWorkers = value;
+      }
+    }
+
     public IEnumerable<IOptimizer> NestedOptimizers {
       get {
@@ -111,4 +121,5 @@
     private bool experimentStarted = false;
     private bool experimentStopped = false;
+
     private readonly ManualResetEventSlim allOptimizerFinished = new ManualResetEventSlim(false); // this indicates that all started optimizers have been paused or stopped
 
@@ -155,4 +166,5 @@
       experimentStarted = original.experimentStarted;
       experimentStopped = original.experimentStopped;
+      numberOfWorkers = original.numberOfWorkers;
       Initialize();
     }
@@ -192,16 +204,32 @@
       if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
         throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
-      if (!Optimizers.Any(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)) return;
+
+      // Multiple enumerations of runnableOptimizers is done on purpose to get the latest list of runnnable optimizers lazily
+      var runnableOptimizers = Optimizers.Where(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused);
+      if (!runnableOptimizers.Any()) return;
 
       experimentStarted = true;
       experimentStopped = false;
-      allOptimizerFinished.Reset();
-      IOptimizer optimizer;
-      while ((optimizer = Optimizers.FirstOrDefault(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)) != null) {
-        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-        try { optimizer.Start(cancellationToken); } catch (InvalidOperationException) { }
-        if (ExecutionState == ExecutionState.Paused || ExecutionState == ExecutionState.Stopped) break;
-      }
-      allOptimizerFinished.Wait();
+
+      var startedOptimizers = new Dictionary<IOptimizer, Task>(); // track already started optimizers (.StartAsync does not set the executionstate immediately)
+      using (var availableWorkers = new SemaphoreSlim(NumberOfWorkers, NumberOfWorkers)) {
+        while (runnableOptimizers.Any(o => !startedOptimizers.ContainsKey(o))) {
+          try {
+            availableWorkers.Wait(cancellationToken);
+            if (experimentStopped || !experimentStarted) break;
+            var optimizer = runnableOptimizers.FirstOrDefault(o => !startedOptimizers.ContainsKey(o));
+            if (optimizer != null) {
+              var startedTask = optimizer.StartAsync(cancellationToken).ContinueWith(async t => {
+                availableWorkers.Release(); // is guaranteed to be not disposed yet because Task.WaitAll blocks before the end of the using
+                await t; // trigger a potential exception on the optimizerTask
+              });
+              startedOptimizers.Add(optimizer, startedTask.Unwrap()); // unwrap task because lambda of .ContinueWith is async
+            }
+          } catch (InvalidOperationException) { } catch (OperationCanceledException) { }
+        }
+
+        Task.WaitAll(startedOptimizers.Values.ToArray()); // retreive exeptions of the asyncrounously started optimizer
+        allOptimizerFinished.Wait();
+      }
     }
     public async Task StartAsync() { await StartAsync(CancellationToken.None); }
@@ -218,5 +246,5 @@
       foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
         // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-        try { optimizer.Pause(); } catch (InvalidOperationException) { }
+        try { optimizer.Pause(); } catch (InvalidOperationException) { } catch (NotSupportedException) { }
       }
     }
@@ -372,6 +400,10 @@
     }
     private void optimizer_Paused(object sender, EventArgs e) {
-      lock (locker)
-        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) OnPaused();
+      lock (locker) {
+        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) {
+          OnPaused();
+        }
+        experimentStarted = false;
+      }
     }
     private void optimizer_Prepared(object sender, EventArgs e) {
@@ -389,6 +421,9 @@
         } else {
           if (experimentStarted && Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) return;
-          else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) OnStopped();
-          else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) OnPaused();
+          else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) {
+            OnStopped();
+          } else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) {
+            OnPaused();
+          }
         }
       }
