Skip to content

Commit

Permalink
Fixed pause bug
Browse files Browse the repository at this point in the history
  • Loading branch information
ZviRosenfeldCx committed Aug 21, 2019
1 parent 6935390 commit 4504c3b
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 39 deletions.
57 changes: 52 additions & 5 deletions GeneticAlgorithm.UnitTests/StartAndPauseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,78 @@ public void IsRunningTest(bool engineRunning)
[TestMethod]
[DataRow(true)]
[DataRow(false)]
public void PuaseReturnValueTest(bool engineRunning)
public void PauseReturnValueTest(bool engineRunning)
{
var engine = GetEngine();
if (engineRunning)
Task.Run(() => engine.Run());

Thread.Sleep(10);
var running = engine.Puase();
var running = engine.Pause();
Assert.AreEqual(engineRunning, running);
}

[TestMethod]
public void PuaseTest()
public void PauseTest()
{
var engine = GetEngine();
Task.Run(() => engine.Run());

Thread.Sleep(10);
engine.Puase();
Thread.Sleep(10);
engine.Pause();
Assert.AreEqual(false, engine.IsRunning);

Task.Run(() => engine.Run()); // Assert that we can start a new scan
}

[TestMethod]
public void RunAfterPauseTest()
{
var engine = GetEngine();
Task.Run(() => engine.Run());
Thread.Sleep(10);

engine.Pause();

Task.Run(() => engine.Run());
Thread.Sleep(10);

Assert.AreEqual(true, engine.IsRunning, "Engine should be running");
}

[TestMethod]
public void RunAfterPauseTest2()
{
var engine = GetEngine();
Task.Run(() => engine.Run());
Thread.Sleep(10);

engine.Pause();

Task.Run(() => engine.Run());
Thread.Sleep(10);

engine.Pause();

Task.Run(() => engine.Run());
Thread.Sleep(10);

Assert.AreEqual(true, engine.IsRunning, "Engine should be running");
}

[TestMethod]
public void PauseReturnValueTest()
{
var engine = GetEngine();
var result = engine.Pause();
Assert.IsFalse(result, "Engine shouldn't have been running");

Task.Run(() => engine.Run());
Thread.Sleep(10);
result = engine.Pause();
Assert.IsTrue(result, "Engine should have been running");
}

private void AssertExceptionIsThrown(Action func, Type exceptionType)
{
try
Expand Down
9 changes: 9 additions & 0 deletions GeneticAlgorithm/Exceptions/CouldntStopEngineException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace GeneticAlgorithm.Exceptions
{
public class CouldntStopEngineException : GeneticAlgorithmException
{
public CouldntStopEngineException() : base("Couldn't stop the engine")
{
}
}
}
95 changes: 61 additions & 34 deletions GeneticAlgorithm/GeneticSearchEngine.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using System;
using System.Threading;
using GeneticAlgorithm.Exceptions;
using GeneticAlgorithm.Interfaces;

namespace GeneticAlgorithm
{
public class GeneticSearchEngine
public class GeneticSearchEngine : IDisposable
{
private readonly object lockObject = new object();
private readonly TimeSpan pauseTimeout = TimeSpan.FromMinutes(1);
private readonly object runLock = new object();
private readonly object pauseLock = new object();
private readonly ManualResetEvent engineFinishedEvent = new ManualResetEvent(true);
private readonly InternalEngine engine;
private readonly ResultBuilder resultBuilder;
private readonly GeneticSearchOptions options;
Expand Down Expand Up @@ -34,8 +38,7 @@ public GeneticSearchEngine(GeneticSearchOptions options, IPopulationGenerator po
/// </summary>
public GeneticSearchResult Run()
{
TryToStart();
try
return RunAsCriticalBlock(() =>
{
while (!ShouldPause)
{
Expand All @@ -45,52 +48,77 @@ public GeneticSearchResult Run()
if (lastResult.IsCompleted) break;
}
return resultBuilder.Build(generation);
}
finally
{
IsRunning = false;
}
});
}

private void TryToStart()
private T RunAsCriticalBlock<T>(Func<T> func)
{
lock (lockObject)
lock (runLock)
{
if (IsRunning)
throw new EngineAlreadyRunningException();
IsRunning = true;
}

try
{
engineFinishedEvent.Reset();
return func();
}
finally
{
lock (runLock)
{
IsRunning = false;
engineFinishedEvent.Set();
}
}
}

/// <summary>
/// Creates the next generation.
/// </summary>
public GeneticSearchResult Next()
{
TryToStart();
try
return RunAsCriticalBlock(() =>
{
generation++;
lastResult = engine.RunSingleGeneration(lastResult?.Population, generation);
resultBuilder.AddGeneration(lastResult);
resultBuilder.AddGeneration(lastResult);
return resultBuilder.Build(generation);
}
finally
{
IsRunning = false;
}
});
}


/// <summary>
/// Puases the search (if it is running).
/// Pauses the search (if it is running).
/// Returns true if the search is running; false otherwise.
/// </summary>
public bool Puase()
/// <returns>True if the search is running; false otherwise</returns>
public bool Pause()
{
if (!IsRunning)
return false;

ShouldPause = true;
return true;
lock (pauseLock)
{
if (!IsRunning)
return false;

try
{
ShouldPause = true;
engineFinishedEvent.WaitOne(pauseTimeout);
if (IsRunning)
throw new CouldntStopEngineException();

return true;
}
finally
{
ShouldPause = false;
}
}
}

/// <summary>
Expand All @@ -105,16 +133,13 @@ public GeneticSearchResult RenewPopulation(double percentageToRenew)
if (percentageToRenew <= 0 || percentageToRenew > 1)
throw new GeneticAlgorithmException($"{nameof(percentageToRenew)} must be between 0 (not including) and 1 (including).");

lock (lockObject)
return RunAsCriticalBlock(() =>
{
if (IsRunning)
throw new EngineAlreadyRunningException();

generation++;
lastResult = engine.RenewPopulationAndUpdatePopulation(percentageToRenew, lastResult.Population);
lastResult = engine.RenewPopulationAndUpdatePopulation(percentageToRenew, lastResult.Population);
resultBuilder.AddGeneration(lastResult);
return resultBuilder.Build(generation);
}
});
}

/// <summary>
Expand All @@ -137,16 +162,18 @@ public GeneticSearchResult SetCurrentPopulation(IChromosome[] newPopulation)
if (newPopulation.Length != options.PopulationSize)
throw new GeneticAlgorithmException($"Population size isn't right. Expected {options.PopulationSize}; got {newPopulation.Length}");

lock (lockObject)
return RunAsCriticalBlock(() =>
{
if (IsRunning)
throw new EngineAlreadyRunningException();

generation++;
lastResult = engine.ConvertPopulationAndUpdatePopulation(newPopulation);
resultBuilder.AddGeneration(lastResult);
return resultBuilder.Build(generation);
}
});
}

public void Dispose()
{
engineFinishedEvent?.Dispose();
}
}
}
5 changes: 5 additions & 0 deletions UserControls/GeneticResultDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public void SetResult(GeneticSearchResult result)
chromosomesView.DataSource = displayChromosomesCollection;
chromosomesView.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

if (result.Environment == null)
environmentPanel.Hide();
else
environmentPanel.Show();

Refresh();
}
}
Expand Down

0 comments on commit 4504c3b

Please sign in to comment.