When to dispose of System.Threading.Task with child tasks?
I have a task that launches several child tasks. (e.g., Task A creates B,C,D,E,F). I also create a System.Threading.Timer
to poll a database every 10 seconds to check if the scheduled item was cancelled by request. If it does, it sets CancellationTokenSource
so that the task knows to cancel. Each sub-task, in this case B,C,D,E,F, will cancel when appropriate (they are looping thru files and moving them around).
Since Task
implements IDisposable
, I want to know if it is a good idea to call Task.WaitAll
again from the catch
block, to wait for the cancellations to propogate. While the cancellation request will be processed, the sub-tasks may be in the middle of a loop and can't cancel until that completes
However, per MSDN:
Always call Dispose before you release your last reference to the Task. Otherwise, the resources it is using will not be freed until the garbage collector calls the Task object's Finalize method.
Should I call wait again on my task array in order to properly call Dispose()
on each task in the array?
public class MyCancelObject
{
CancellationTokenSource Source { get;set;}
int DatabaseId { get;set;}
}
private void CheckTaskCancelled(object state)
{
MyCancelObject sourceToken = (MyCancelObject)state;
if (!sourceToken.CancelToken.IsCancellationRequested)
{
开发者_如何学C //Check database to see if cancelled -- if so, set to cancelled
sourceToken.CancelToken.Cancel();
}
}
private void SomeFunc()
{
Task.StartNew( () =>
{
MyCancelObject myCancelObject = new MyCancelObject(
databaseId,
new CancellationTokenSource());
System.Threading.Timer cancelTimer = new Timer(
new TimerCallback(CheckIfTaskCancelled),
myCancelObject,
10000,
10000);
Task[] someTasks = new Task[someNumberOfTasks];
for (int i = 0; i < someNumberOfTasks; i++)
someTasks[i] = Task.Factory.StartNew(
() =>
{
DoSomeWork(someObject, myCancelObject.CancelToken.Token);
},
TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning,
myCancelObject.CancelToken.Token);
try
{
Task.WaitAll(someTasks, cts);
}
catch (AggregateException)
{
//Do stuff to handle
}
catch (OperationCanceledException)
{
//Should I call Task.WaitAll(someTasks) again??
//I want to be able to dispose.
}
}
}
I feel like I have figured this out, but anyone that would like to add anything else useful is more than welcome.
I simply called Task.WaitAll()
again from the catch block to wait for the other tasks to finish. After they have all finished, I have a finally block cleaning up all tasks in the array.
try
{
Task.WaitAll(someTaskArray, cancelToken)
}
catch (OperationCanceledException)
{
Task.WaitAll(someTaskArray);
}
finally
{
for (int i = 0; i < someTaskArray.Length; i++)
someTaskArray[i].Dispose();
}
精彩评论