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>
public virtual void End() {
// Use some ingenious double-checked locking to set the endCalled flag.
// Quite a lot of effort for a mere safety feature that prevents the programmer
// from calling End() twice.
bool error;
if(!this.endCalled) {
// By design, end can only be called once!
lock(this) {
if(!this.endCalled) {
this.endCalled = true;
error = false;
} else {
error = true;
}
} // lock
} else {
error = true;
}
if(error)
if(this.endCalled)
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(!Ended)
WaitHandle.WaitOne();

View File

@ -302,6 +302,25 @@ namespace Nuclex.Support.Tracking {
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>
/// <param name="tracker">Tracker to mock an event subscriber for</param>
/// <returns>The mocked event subscriber</returns>

View File

@ -189,7 +189,7 @@ namespace Nuclex.Support.Tracking {
observedProgression.Dispose();
}
}
} // if progression ended
} // lock
@ -213,6 +213,7 @@ namespace Nuclex.Support.Tracking {
{
ObservedWeightedProgression<Progression> wrappedProgression =
this.trackedProgressions[removeIndex];
this.trackedProgressions.RemoveAt(removeIndex);
wrappedProgression.Dispose();
}
@ -295,7 +296,7 @@ namespace Nuclex.Support.Tracking {
this.progress = totalProgress;
OnAsyncProgressUpdated(totalProgress);
}
} // lock
}
/// <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.
setIdle(true);
}
} // lock
}
/// <summary>Called when one of the tracked progression has achieved progress</summary>
@ -338,6 +339,10 @@ namespace Nuclex.Support.Tracking {
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>
private volatile float totalWeight;
/// <summary>Progressions being tracked by this tracker</summary>
@ -346,10 +351,6 @@ namespace Nuclex.Support.Tracking {
private ObservedWeightedProgression<Progression>.ReportDelegate asyncEndedDelegate;
/// <summary>Delegate for the asyncProgressUpdated() method</summary>
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;
}