2012-09-13 176 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方法取消它,從工作主體不只是退出。