Some more unit tests; improved documentation; improve useless speed optimization of an exceptional case
git-svn-id: file:///srv/devel/repo-conversion/nusu@39 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
81cb56f468
commit
acbb07d6b5
|
@ -39,24 +39,13 @@ namespace Nuclex.Support.Scheduling {
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual void End() {
|
public virtual void End() {
|
||||||
|
|
||||||
// Use some ingenious double-checked locking to set the endCalled flag.
|
// By design, end can only be called once!
|
||||||
// Quite a lot of effort for a mere safety feature that prevents the programmer
|
lock(this) {
|
||||||
// from calling End() twice.
|
if(this.endCalled)
|
||||||
bool error;
|
throw new InvalidOperationException("End() has already been called");
|
||||||
if(!this.endCalled) {
|
|
||||||
lock(this) {
|
this.endCalled = true;
|
||||||
if(!this.endCalled) {
|
|
||||||
this.endCalled = true;
|
|
||||||
error = false;
|
|
||||||
} else {
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
} // lock
|
|
||||||
} else {
|
|
||||||
error = true;
|
|
||||||
}
|
}
|
||||||
if(error)
|
|
||||||
throw new InvalidOperationException("End() has already been called");
|
|
||||||
|
|
||||||
// If the progression itself hasn't ended yet, block the caller until it has.
|
// If the progression itself hasn't ended yet, block the caller until it has.
|
||||||
if(!Ended)
|
if(!Ended)
|
||||||
|
|
|
@ -302,6 +302,25 @@ namespace Nuclex.Support.Tracking {
|
||||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to provoke a deadlock by re-entering the tracker from one of
|
||||||
|
/// its own events.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestProvokedDeadlock() {
|
||||||
|
ProgressionTracker tracker = new ProgressionTracker();
|
||||||
|
|
||||||
|
TestProgression test1 = new TestProgression();
|
||||||
|
tracker.Track(test1);
|
||||||
|
|
||||||
|
tracker.AsyncIdleStateChanged +=
|
||||||
|
(EventHandler<IdleStateEventArgs>)delegate(object sender, IdleStateEventArgs arguments) {
|
||||||
|
tracker.Track(Progression.EndedDummy);
|
||||||
|
};
|
||||||
|
|
||||||
|
test1.End();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Mocks a subscriber for the events of a tracker</summary>
|
/// <summary>Mocks a subscriber for the events of a tracker</summary>
|
||||||
/// <param name="tracker">Tracker to mock an event subscriber for</param>
|
/// <param name="tracker">Tracker to mock an event subscriber for</param>
|
||||||
/// <returns>The mocked event subscriber</returns>
|
/// <returns>The mocked event subscriber</returns>
|
||||||
|
|
|
@ -189,7 +189,7 @@ namespace Nuclex.Support.Tracking {
|
||||||
observedProgression.Dispose();
|
observedProgression.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // if progression ended
|
||||||
|
|
||||||
} // lock
|
} // lock
|
||||||
|
|
||||||
|
@ -213,6 +213,7 @@ namespace Nuclex.Support.Tracking {
|
||||||
{
|
{
|
||||||
ObservedWeightedProgression<Progression> wrappedProgression =
|
ObservedWeightedProgression<Progression> wrappedProgression =
|
||||||
this.trackedProgressions[removeIndex];
|
this.trackedProgressions[removeIndex];
|
||||||
|
|
||||||
this.trackedProgressions.RemoveAt(removeIndex);
|
this.trackedProgressions.RemoveAt(removeIndex);
|
||||||
wrappedProgression.Dispose();
|
wrappedProgression.Dispose();
|
||||||
}
|
}
|
||||||
|
@ -295,7 +296,7 @@ namespace Nuclex.Support.Tracking {
|
||||||
this.progress = totalProgress;
|
this.progress = totalProgress;
|
||||||
OnAsyncProgressUpdated(totalProgress);
|
OnAsyncProgressUpdated(totalProgress);
|
||||||
|
|
||||||
}
|
} // lock
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Called when one of the tracked progressions has ended</summary>
|
/// <summary>Called when one of the tracked progressions has ended</summary>
|
||||||
|
@ -319,7 +320,7 @@ namespace Nuclex.Support.Tracking {
|
||||||
// progressions were finished, so it's safe to trigger this here.
|
// progressions were finished, so it's safe to trigger this here.
|
||||||
setIdle(true);
|
setIdle(true);
|
||||||
|
|
||||||
}
|
} // lock
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Called when one of the tracked progression has achieved progress</summary>
|
/// <summary>Called when one of the tracked progression has achieved progress</summary>
|
||||||
|
@ -338,6 +339,10 @@ namespace Nuclex.Support.Tracking {
|
||||||
OnAsyncIdleStateChanged(idle);
|
OnAsyncIdleStateChanged(idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Whether the tracker is currently idle</summary>
|
||||||
|
private volatile bool idle;
|
||||||
|
/// <summary>Current summed progress of the tracked progressions</summary>
|
||||||
|
private volatile float progress;
|
||||||
/// <summary>Total weight of all progressions being tracked</summary>
|
/// <summary>Total weight of all progressions being tracked</summary>
|
||||||
private volatile float totalWeight;
|
private volatile float totalWeight;
|
||||||
/// <summary>Progressions being tracked by this tracker</summary>
|
/// <summary>Progressions being tracked by this tracker</summary>
|
||||||
|
@ -346,10 +351,6 @@ namespace Nuclex.Support.Tracking {
|
||||||
private ObservedWeightedProgression<Progression>.ReportDelegate asyncEndedDelegate;
|
private ObservedWeightedProgression<Progression>.ReportDelegate asyncEndedDelegate;
|
||||||
/// <summary>Delegate for the asyncProgressUpdated() method</summary>
|
/// <summary>Delegate for the asyncProgressUpdated() method</summary>
|
||||||
private ObservedWeightedProgression<Progression>.ReportDelegate asyncProgressUpdatedDelegate;
|
private ObservedWeightedProgression<Progression>.ReportDelegate asyncProgressUpdatedDelegate;
|
||||||
/// <summary>Whether the tracker is currently idle</summary>
|
|
||||||
private bool idle;
|
|
||||||
/// <summary>Current summed progress of the tracked progressions</summary>
|
|
||||||
private volatile float progress;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user