Index: branches/ParallelExperiment/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs
===================================================================
--- branches/ParallelExperiment/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs	(revision 15334)
+++ branches/ParallelExperiment/HeuristicLab.Optimization.Views/3.3/ExperimentView.Designer.cs	(revision 15337)
@@ -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: branches/ParallelExperiment/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs
===================================================================
--- branches/ParallelExperiment/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs	(revision 15334)
+++ branches/ParallelExperiment/HeuristicLab.Optimization.Views/3.3/ExperimentView.cs	(revision 15337)
@@ -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: branches/ParallelExperiment/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs
===================================================================
--- branches/ParallelExperiment/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 15334)
+++ branches/ParallelExperiment/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 15337)
@@ -80,11 +80,8 @@
       try {
         Run((object)cancellationTokenSource.Token);
-      }
-      catch (OperationCanceledException) {
-      }
-      catch (AggregateException ae) {
+      } catch (OperationCanceledException) {
+      } catch (AggregateException ae) {
         OnExceptionOccurred(ae.InnerExceptions.SingleOrDefault() ?? ae);
-      }
-      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: branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs
===================================================================
--- branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 15334)
+++ branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 15337)
@@ -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() {
@@ -385,5 +386,5 @@
     }
     private void Optimizer_Prepared(object sender, EventArgs e) {
-      if (batchRunAction == BatchRunAction.Prepare || ExecutionState == ExecutionState.Stopped) {
+      if (batchRunAction == BatchRunAction.Prepare/* || ExecutionState == ExecutionState.Stopped*/) {
         ExecutionTime = TimeSpan.Zero;
         runsExecutionTime = TimeSpan.Zero;
Index: branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs
===================================================================
--- branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 15334)
+++ branches/ParallelExperiment/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 15337)
@@ -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,7 @@
     private bool experimentStarted = false;
     private bool experimentStopped = false;
+
     private ManualResetEventSlim allOptimizerFinished; // this indicates that all started optimizers have been paused or stopped
+    private SemaphoreSlim availableWorkers; // limits the number of concurrent optimizer executions
 
     public Experiment()
@@ -155,4 +167,5 @@
       experimentStarted = original.experimentStarted;
       experimentStopped = original.experimentStopped;
+      numberOfWorkers = original.numberOfWorkers;
       Initialize();
     }
@@ -189,4 +202,5 @@
       Start(CancellationToken.None);
     }
+
     public void Start(CancellationToken cancellationToken) {
       if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
@@ -197,10 +211,19 @@
       experimentStopped = false;
       allOptimizerFinished = new ManualResetEventSlim(false);
-
-      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;
+      availableWorkers = new SemaphoreSlim(NumberOfWorkers, NumberOfWorkers);
+
+      var runnableOptimizers = Optimizers.Where(o => o.ExecutionState == ExecutionState.Prepared || o.ExecutionState == ExecutionState.Paused).ToList();
+      if (!runnableOptimizers.Any()) return;
+
+      while (runnableOptimizers.Any()) {
+        try {
+          availableWorkers.Wait(cancellationToken); // an optimizer was pause/stopped previously
+          if (experimentStopped || !experimentStarted) break;
+          // some optimizers might be started manually somewhere else
+          runnableOptimizers.RemoveAll(o => !(o.ExecutionState == ExecutionState.Prepared || o.ExecutionState == ExecutionState.Paused));
+          var optimizer = runnableOptimizers.FirstOrDefault();
+          runnableOptimizers.Remove(optimizer);
+          optimizer?.StartAsync(cancellationToken);
+        } catch (InvalidOperationException) { } catch (OperationCanceledException) { }
       }
 
@@ -220,5 +243,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) { }
       }
     }
@@ -273,4 +296,5 @@
       EventHandler handler = Paused;
       if (handler != null) handler(this, EventArgs.Empty);
+      allOptimizerFinished.Set();
     }
     public event EventHandler Stopped;
@@ -279,4 +303,5 @@
       EventHandler handler = Stopped;
       if (handler != null) handler(this, EventArgs.Empty);
+      allOptimizerFinished.Set();
     }
     public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
@@ -372,9 +397,11 @@
     }
     private void optimizer_Paused(object sender, EventArgs e) {
-      lock (locker)
+      lock (locker) {
+        if (availableWorkers.CurrentCount < NumberOfWorkers)
+          availableWorkers.Release();
         if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) {
           OnPaused();
-          allOptimizerFinished.Set();
-        }
+        }
+      }
     }
     private void optimizer_Prepared(object sender, EventArgs e) {
@@ -388,8 +415,9 @@
     private void optimizer_Stopped(object sender, EventArgs e) {
       lock (locker) {
+        if (availableWorkers.CurrentCount < NumberOfWorkers)
+          availableWorkers.Release();
         if (experimentStopped) {
           if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) {
             OnStopped();
-            allOptimizerFinished.Set();
           }
         } else {
@@ -397,8 +425,6 @@
           else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) {
             OnStopped();
-            allOptimizerFinished.Set();
           } else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) {
             OnPaused();
-            allOptimizerFinished.Set();
           }
         }
