2012-09-13 46 views
0

取消正在执行的任务我有我需要依次处理(但在一个单独的工作线程,从而保持用户界面的响应)的项目清单。重要的是要注意的是,这些项目可以运行很长时间(5 - 10秒)。在任务队列

Task<bool> currentTask = null; 

foreach (var item in items) 
{ 
    var currentItem = item; 

    // Add a new task to the sequential task queue 
    if (currentTask == null) 
     currentTask = Task.Factory.StartNew<bool>(() => 
     { 
      return currentItem.ProcessItem(); 
     }, processCancelTokenSource.Token); 
    else 
     currentTask = currentTask.ContinueWith<bool>(t => 
     { 
      return currentItem.ProcessItem(); 
     }, processCancelTokenSource.Token); 

    // Update UI after each task completes 
    currentTask.ContinueWith(t => 
    { 
     if (t.IsCanceled) 
      currentItem.State = State.Cancelled; 
     else 
     { 
      if (t.Result) 
       currentItem.State = State.Complete; 
      else 
       currentItem.State = State.Failed; 
     } 
    },TaskScheduler.FromCurrentSynchronizationContext()); 
} 

现在,我使用的是CancellationToken取消队列的处理(有一个“取消处理”按钮)。

的问题是,这并没有取消目前正在执行的任务。如果CancellationTokenSource.Cancel()被调用,那么所有的等待队列中要执行的任务将被取消和他们的项目的currentItem.State将被设置为State.Cancelled,这是正确的。问题是取消时正在执行的任务将继续执行,直至完成,然后设置为State.CompleteState.Failed。这并不理想,原因有两个:(1)取消后任务仍在运行,(2)状态未设置为State.Cancelled,因为t.IsCanceled不正确。

有没有办法对我来说,安全地取消/停止当前正在执行的任务?

+1

是的,只是代码正是你想要的。没有魔法,秘密简单的方法。您必须指定将支持中断的每个任务在哪里以及如何中断,可能通过在方便的位置检查其任务结构来查看它是否被取消。 –

+1

在你的'ProcessItem'方法中,你可以传入'CancellationToken'并定期调用'ThrowIfCancellationRequested'。 –

+0

问题是我无法以任何方式重新设计ProcessItem()。 – davenewza

回答

4

任务支持优雅的取消模式。 CancellationToken只是一个令牌。它不会中断任何正在执行的代码或中止一个线程。您应该自己在任务主体中检查此令牌。

有一点要记住:如果你想获得你当前的任务取消,通过CancellationToken.ThrowIfCancellationRequested方法取消它,从工作主体不只是退出。