Index: /stable/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs
===================================================================
--- /stable/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs	(revision 15572)
+++ /stable/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs	(revision 15573)
@@ -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: /stable/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs
===================================================================
--- /stable/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs	(revision 15572)
+++ /stable/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs	(revision 15573)
@@ -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;
       }
     }
@@ -53,4 +56,5 @@
       experimentTreeView.Enabled = Content != null;
       runsViewHost.Enabled = Content != null;
+      workersNumericUpDown.Enabled = Content != null && Content.ExecutionState != ExecutionState.Started;
     }
 
@@ -66,4 +70,16 @@
       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) {
+      if (Content != null)
+        Content.NumberOfWorkers = (int)workersNumericUpDown.Value;
+    }
+    #endregion
   }
 }
Index: /stable/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs
===================================================================
--- /stable/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 15572)
+++ /stable/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 15573)
@@ -21,5 +21,4 @@
 
 using System;
-using System.Linq;
 using System.Threading;
 using HeuristicLab.Common;
@@ -80,11 +79,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 +100,5 @@
       base.Pause();
       pausePending = true;
-      CancellationTokenSource.Cancel();
+      if (CancellationTokenSource != null) CancellationTokenSource.Cancel();
     }
 
@@ -112,5 +108,5 @@
       base.Stop();
       if (ExecutionState == ExecutionState.Paused) OnStopped();
-      else CancellationTokenSource.Cancel();
+      else if (CancellationTokenSource != null) CancellationTokenSource.Cancel();
     }
 
@@ -127,6 +123,5 @@
         initialized = true;
         Run(cancellationToken);
-      }
-      finally {
+      } finally {
         timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
         timer.Stop();
Index: /stable/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs
===================================================================
--- /stable/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 15572)
+++ /stable/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 15573)
@@ -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: /stable/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs
===================================================================
--- /stable/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 15572)
+++ /stable/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 15573)
@@ -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,5 +121,15 @@
     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
+
+    // track already started optimizers (.StartAsync does not set the executionstate immediately)
+    // and to avoid restarting optimizers that were manually paused/stopped by the user
+    private readonly IDictionary<IOptimizer, Task> startedOptimizers = new Dictionary<IOptimizer, Task>();
+    private IEnumerable<IOptimizer> StartableOptimizers {
+      get {
+        return Optimizers
+          .Where(x => x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused)
+          .Where(o => !startedOptimizers.ContainsKey(o));  // all startable optimizers that were not startet yet
+      }
+    }
 
     public Experiment()
@@ -155,4 +175,5 @@
       experimentStarted = original.experimentStarted;
       experimentStopped = original.experimentStopped;
+      numberOfWorkers = original.numberOfWorkers;
       Initialize();
     }
@@ -192,16 +213,28 @@
       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;
+
+      startedOptimizers.Clear();
+      if (!StartableOptimizers.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();
+
+      using (var availableWorkers = new SemaphoreSlim(NumberOfWorkers, NumberOfWorkers)) {
+        while (StartableOptimizers.Any()) {
+          try {
+            availableWorkers.Wait(cancellationToken);
+            var optimizer = StartableOptimizers.FirstOrDefault();
+            if (experimentStopped || !experimentStarted || optimizer == null) break;
+
+            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()); // retrieve exeptions of the asyncrounously started optimizer
+      }
     }
     public async Task StartAsync() { await StartAsync(CancellationToken.None); }
@@ -218,5 +251,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) { }
       }
     }
@@ -256,4 +289,5 @@
     public event EventHandler Prepared;
     private void OnPrepared() {
+      if (ExecutionState == ExecutionState.Prepared) return;
       ExecutionState = ExecutionState.Prepared;
       EventHandler handler = Prepared;
@@ -262,4 +296,5 @@
     public event EventHandler Started;
     private void OnStarted() {
+      if (ExecutionState == ExecutionState.Started) return;
       ExecutionState = ExecutionState.Started;
       EventHandler handler = Started;
@@ -268,6 +303,6 @@
     public event EventHandler Paused;
     private void OnPaused() {
+      if (ExecutionState == ExecutionState.Paused) return;
       ExecutionState = ExecutionState.Paused;
-      allOptimizerFinished.Set();
       EventHandler handler = Paused;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -275,6 +310,6 @@
     public event EventHandler Stopped;
     private void OnStopped() {
+      if (ExecutionState == ExecutionState.Stopped) return;
       ExecutionState = ExecutionState.Stopped;
-      allOptimizerFinished.Set();
       EventHandler handler = Stopped;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -372,10 +407,8 @@
     }
     private void optimizer_Paused(object sender, EventArgs e) {
-      lock (locker)
-        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) OnPaused();
+      UpdateExecutionState();
     }
     private void optimizer_Prepared(object sender, EventArgs e) {
-      lock (locker)
-        if (Optimizers.All(x => x.ExecutionState == ExecutionState.Prepared)) OnPrepared();
+      UpdateExecutionState();
     }
     private void optimizer_Started(object sender, EventArgs e) {
@@ -384,14 +417,44 @@
     }
     private void optimizer_Stopped(object sender, EventArgs e) {
+      UpdateExecutionState();
+    }
+    private void UpdateExecutionState() {
+      // Execution states of the Experiment are determined using the following _basic_ rules:
+      //   if any Optimizer is Started      => Experiment is Started  (2. if)
+      //   if any Optimizer is Paused       => Experiment is Paused   (3. if)
+      //   if any Optimizer is Prepared     => Experiment is Prepared (5. if)
+      //   else (all Optimizer are Stopped) => Experiment is Stopped  (6. if)
+      // Additional there are two extra rules:
+      //   if the Experiment is running and there are still optimizers that can be started => keep the Experiment Running (1. if)
+      //   if experiment-stop is pending: Stop Experiment even if there are still Prepared Optimizer               (4. if)
+
       lock (locker) {
-        if (experimentStopped) {
-          if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) OnStopped();
-        } 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();
-        }
-      }
-    }
+        // 1. experiment is running & further startable optimizers are available => continue executing
+        if (experimentStarted && StartableOptimizers.Any())
+          return;
+
+        // 2. any optimizer is running => continue executing
+        if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Started))
+          return;
+
+        experimentStarted = false;
+        // 3. any optimizer is paused => experiment paused
+        if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Paused))
+          OnPaused();
+
+        // 4. stop pending & all optimizers either stopped or prepared => experiment stopped
+        else if (experimentStopped)
+          OnStopped();
+
+        // 5. any optimizer prepared => experiment prepared
+        else if (Optimizers.Any(x => x.ExecutionState == ExecutionState.Prepared))
+          OnPrepared();
+
+        // 6. (else) all optimizers stopped
+        else
+          OnStopped();
+      }
+    }
+
     private void optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
       lock (runsLocker) {
