Made the ParallelBackgroundWorker.CancelRunningTasks() and .CancelPendingTasks() methods safe to call after Dispose() (since many usage patterns become much easier with this allowed); Wait() didn't wait for queued tasks (though as long as tasks are queued, there will always be executing tasks, so this is just me being pedantic) - fixed; fixed a race condition in one of the unit tests for the ParallelBackgroundWorker
git-svn-id: file:///srv/devel/repo-conversion/nusu@293 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
a2b92248b5
commit
0a7306bb58
|
@ -95,7 +95,9 @@ namespace Nuclex.Support {
|
|||
this.WasCancelled = cancellationToken.IsCancellationRequested;
|
||||
|
||||
if(this.Tasks != null) {
|
||||
this.Tasks.Add(task);
|
||||
lock(this.Tasks) {
|
||||
this.Tasks.Add(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +238,9 @@ namespace Nuclex.Support {
|
|||
waitEvent.Set();
|
||||
testWorker.Join();
|
||||
|
||||
CollectionAssert.AreEquivalent(tasks, testWorker.Tasks);
|
||||
lock(testWorker.Tasks) {
|
||||
CollectionAssert.AreEquivalent(tasks, testWorker.Tasks);
|
||||
}
|
||||
}
|
||||
} // disposes waitEvent
|
||||
}
|
||||
|
|
|
@ -94,9 +94,11 @@ namespace Nuclex.Support {
|
|||
this.threadTerminatedEvent.Dispose();
|
||||
this.threadTerminatedEvent = null;
|
||||
}
|
||||
if(this.cancellationTokenSource != null) {
|
||||
this.cancellationTokenSource.Dispose();
|
||||
this.cancellationTokenSource = null;
|
||||
lock(this.queueSynchronizationRoot) {
|
||||
if(this.cancellationTokenSource != null) {
|
||||
this.cancellationTokenSource.Dispose();
|
||||
this.cancellationTokenSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,11 +134,21 @@ namespace Nuclex.Support {
|
|||
}
|
||||
|
||||
/// <summary>Cancels all tasks that are currently executing</summary>
|
||||
/// <remarks>
|
||||
/// It is valid to call this method after Dispose()
|
||||
/// </remarks>
|
||||
public void CancelRunningTasks() {
|
||||
this.cancellationTokenSource.Cancel();
|
||||
lock(this.queueSynchronizationRoot) {
|
||||
if(this.cancellationTokenSource != null) {
|
||||
this.cancellationTokenSource.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Cancels all queued tasks waiting to be executed</summary>
|
||||
/// <remarks>
|
||||
/// It is valid to call this method after Dispose()
|
||||
/// </remarks>
|
||||
public void CancelPendingTasks() {
|
||||
lock(this.queueSynchronizationRoot) {
|
||||
this.tasks.Clear();
|
||||
|
@ -166,6 +178,15 @@ namespace Nuclex.Support {
|
|||
/// True if all tasks have been processed, false if the timeout was reached
|
||||
/// </returns>
|
||||
public bool Wait(int timeoutMilliseconds) {
|
||||
|
||||
// Wait until the task queue has become empty
|
||||
while(queuedTaskCount > 0) {
|
||||
if(this.threadTerminatedEvent.WaitOne(timeoutMilliseconds) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now wait until all running tasks have finished
|
||||
while(Thread.VolatileRead(ref this.runningThreadCount) > 0) {
|
||||
if(this.threadTerminatedEvent.WaitOne(timeoutMilliseconds) == false) {
|
||||
return false;
|
||||
|
@ -173,6 +194,7 @@ namespace Nuclex.Support {
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Called in a thread to execute a single task</summary>
|
||||
|
@ -219,6 +241,15 @@ namespace Nuclex.Support {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Number of task still waiting to be executed</summary>
|
||||
private int queuedTaskCount {
|
||||
get {
|
||||
lock(this.queueSynchronizationRoot) {
|
||||
return this.tasks.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name that will be assigned to the worker threads while they're processing tasks
|
||||
/// for the parallel background worker
|
||||
|
|
Loading…
Reference in New Issue
Block a user