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:
Markus Ewald 2007-07-12 22:16:11 +00:00
parent 81cb56f468
commit acbb07d6b5
3 changed files with 33 additions and 24 deletions

View File

@ -39,25 +39,14 @@ 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
// from calling End() twice.
bool error;
if(!this.endCalled) {
lock(this) { lock(this) {
if(!this.endCalled) { 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"); throw new InvalidOperationException("End() has already been called");
this.endCalled = true;
}
// 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)
WaitHandle.WaitOne(); WaitHandle.WaitOne();

View File

@ -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>

View File

@ -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;
} }