简体   繁体   English

什么时候处理带有子任务的System.Threading.Task?

[英]When to dispose of System.Threading.Task with child tasks?

I have a task that launches several child tasks. 我有一个任务,启动几个子任务。 (eg, Task A creates B,C,D,E,F). (例如,任务A创建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. 我还创建了一个System.Threading.Timer来每10秒轮询一次数据库,以检查是否已按请求取消了计划的项目。 If it does, it sets CancellationTokenSource so that the task knows to cancel. 如果是,则设置CancellationTokenSource以便任务知道取消。 Each sub-task, in this case B,C,D,E,F, will cancel when appropriate (they are looping thru files and moving them around). 每个子任务(在本例中为B,C,D,E,F)将在适当时取消(它们通过文件循环并移动它们)。

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. 由于Task实现了IDisposable ,我想知道从catch块再次调用Task.WaitAll是否是个好主意,等待取消传播。 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: 但是,根据MSDN:

Always call Dispose before you release your last reference to the Task. 始终在释放对任务的最后一个引用之前调用Dispose。 Otherwise, the resources it is using will not be freed until the garbage collector calls the Task object's Finalize method. 否则,在垃圾收集器调用Task对象的Finalize方法之前,不会释放它正在使用的资源。

Should I call wait again on my task array in order to properly call Dispose() on each task in the array? 我应该在我的任务数组上再次调用wait,以便在数组中的每个任务上正确调用Dispose()吗?

public class MyCancelObject
{
  CancellationTokenSource Source { get;set;}
  int DatabaseId { get;set;}   
}

private void CheckTaskCancelled(object state)
{
  MyCancelObject sourceToken = (MyCancelObject)state;

  if (!sourceToken.CancelToken.IsCancellationRequested)
  {
    //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. 我只是从catch块再次调用Task.WaitAll()来等待其他任务完成。 After they have all finished, I have a finally block cleaning up all tasks in the array. 完成后,我有一个finally块清理阵列中的所有任务。

try
{
Task.WaitAll(someTaskArray, cancelToken)
}
catch (OperationCanceledException)
{
Task.WaitAll(someTaskArray);
}
finally
{
for (int i = 0; i < someTaskArray.Length; i++)
someTaskArray[i].Dispose();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM