2013-02-14 168 views
10

我有一個耗時的任務,我需要在單獨的線程中運行以避免鎖定GUI線程。隨着此任務的進展,它會更新特定的GUI控件。取消任務並等待它完成

美中不足的是,面前的任務是在用戶可能移動到圖形用戶界面的另一部分,並且在這種情況下,我必須:

  1. 取消正在進行的任務(如果它是活動)
  2. 等到它完成取消:這是至關重要的,因爲耗時的任務的目標是更新特定的控件。如果不止一個線程試圖立即執行,事情可能會變得混亂。
  3. 啓動從頭

任務對於一個具體的例子,設想的形式主要有兩個部分:一是在您瀏覽目錄樹,和另一個在那裏你顯示縮略圖。當用戶導航到另一個目錄時,需要刷新縮略圖。

首先我想到使用BackgroundWorkerAutoResetEvent來等待取消,但是我一定弄錯了一些東西,因爲取消時我被鎖定了。然後我讀了關於TPL,它應該取代BGW和更原始的機制。

這可以使用TPL輕鬆完成嗎?

回答

18

有幾件事情需要注意:

  • 可以從CancellationTokenSource

  • 任務取消獲得CancellationToken合作行動:如果你的任務沒有定期檢查CancellationToken.IsCancellationRequested財產,無論你嘗試取消任務多少次都沒有關係,它會快樂地流失。

那些東西說,這裏的總體思路:

void Main() 
{ 
    var tokenSource = new CancellationTokenSource(); 
    var myTask = Task.Factory 
     .StartNew(() => DoWork(tokenSource.Token), tokenSource.Token); 

    Thread.Sleep(1000); 

    // ok, let's cancel it (well, let's "request it be cancelled") 
    tokenSource.Cancel(); 

    // wait for the task to "finish" 
    myTask.Wait(); 
} 

public void DoWork(CancellationToken token) 
{ 
    while(!token.IsCancellationRequested) 
    { 
     // Do useful stuff here 
     Console.WriteLine("Working!"); 
     Thread.Sleep(100); 
    } 
} 
+0

是否還好只是一次創建令牌源及其令牌傳遞到'StartNew'每一次? – 2013-02-15 12:49:09

+0

把它想象成一個小孩的兩個罐子放在一個串上(好吧,一個給N罐頭:你有一端,所有開始的任務都可以,你一邊喊「取消」,所有分享令牌的人都會聽到它。 – JerKimball 2013-02-15 15:27:17

+1

@dario_ramos我相信你的評論中的問題是在評論[這裏](http://stackoverflow.com/questions/14896248/deadlock-when-waiting-for-task-to-finish)中回答的,但爲了完整性'因此,答案是否定的 - 'CancellationTokenSource'不能被重置和取消;如果你要求取消一個,那麼如果你想再次取消,你必須用一個新的取代它 – shambulator 2013-02-16 12:05:36