2014-12-26 65 views
0

的對消抓到我有一個類Worker這是做了一些工作(與模擬工作負載):異常沒有在Task.Run

public class Worker 
    { ... 

public void DoWork(CancellationToken ct) 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       ct.ThrowIfCancellationRequested(); 
       Thread.Sleep(2000); 
      } 
     } 

現在我想在Task.Run使用這種方法(從我的Windows窗體應用程序,在按鈕點擊),它可以被取消:

private CancellationTokenSource _ctSource; 

try 
      { 
       Task.Run(() => 
       { 
        _worker.DoWork(_ctSource.Token); 
       },_ctSource.Token); 
      } 
      catch (AggregateException aex) 
      { 
       String g = aex.Message; 
      } 
      catch (OperationCanceledException ex) 
      { 
       String g = ex.Message; 
      } 
      catch (Exception ex) 
      { 
       String g = ex.Message; 
      } 

但是,當任務開始,我不能_ctSource.Cancel()取消; 我在視覺工作室中發現錯誤,OperationCanceledException未被處理!

但我圍繞着try-catch-clause中的Task.Run調用!在Worker對象中產生的異常應該拋出或不拋出? 問題是什麼?

+1

'OperationHandledException'?你確定?我從來沒有聽說過這樣的事情。 –

+1

我的意思是OperationCanceledException :-) – rubiktubik

+1

'我在Visual Studio中遇到了OperationCanceledException未處理的錯誤!'只需點擊'F5'並忽略它。當你在VS之外運行它時你不會得到它。順便說一句:你不能像你的代碼那樣捕獲任務的異常。您創建一個任務並退出try塊。 「ContinueWith」可能對此有所幫助。 –

回答

2

您的Task.Run致電創建任務,然後立即返回。它不會拋出。但是它創建的任務可能會失敗或在之後被取消

您在這裏有幾種解決方案:

  • 使用await

    await Task.Run(...) 
    
  • 連接取決於故障/註銷情況的延續:

    var task = Task.Run(...); 
    task.ContinueWith(t => ..., TaskContinuationOptions.OnlyOnCanceled); 
    task.ContinueWith(t => ..., TaskContinuationOptions.OnlyOnFaulted); 
    
  • 連接單繼續失敗:

    Task.Run(...).ContinueWith(t => ..., TaskContinuationOptions.NotOnRanToCompletion); 
    

你可以/應該使用的解決方案取決於周圍的代碼。

+0

你的解決方案不工作,我試着等待和task.ContinueWith(),仍然得到這個錯誤 – rubiktubik

+2

這工作得很好(我upvoted它)。你遇到的問題是你試圖捕獲Task.Run()周圍的異常,並且當異常上升時,主線程的執行早已經過你的try/catch塊。這就是爲什麼異步任務不會在主線程上拋出異常。在任務中的代碼已經運行(任務結束時)之後,您需要檢查異常*,可以通過延續任務或直接檢查返回的任務。 – Jcl

+0

好的,現在我測試了一下,把try-catch-block放到Task.Run中,現在它就抓住了! – rubiktubik

0

您需要新的令牌
private CancellationTokenSource _ctSource = new CancellationTokenSource();

爲什麼要在DoWork中拋出期望?
來自一個線程的異常不會冒泡另一個啓動該線程的線程。

Cancellation in Managed Threads

0

如果並行任務拋出一個異常,它會返回執行,將有它的Exception財產(爲AggregateException,你應該檢查其InnerException)集(和任何其IsCanceledIsFaulted屬性設置爲true)。從我的項目的一些最少的樣品代碼升級的例外主線程:

var t = new Task(Initialize); 
    t.Start(); 
    while (!t.IsCompleted && !t.IsFaulted) 
    { 
    // Do other work in the main thread 
    } 
    if (t.IsFaulted) 
    { 
    if (t.Exception != null) 
    { 
     if(t.Exception.InnerException != null) 
     throw t.Exception.InnerException; 
    } 
    throw new InvalidAsynchronousStateException("Initialization failed for an unknown reason"); 
    } 

如果使用CancellationTokenSource它應該很容易進一步提高這一檢查IsCanceled(而不是IsFaulted

您也可以使用Task.Wait()而不是while循環...在我的項目中,在這種情況下,使用while循環似乎更合適,但是您需要等待Task以某種方式結束。

如果使用Task.Run()你可以使用一個.ContinueWith(Task)這將有傳入的原始任務(在這裏你可以檢查IsFaultedIsCanceled),或者只在斷陷執行運行,在你的意志。