2017-01-10 20 views
-2

我創建了作品鏈。他們將在我的附加線程內工作。爲此我使用Task。另外,如果發生任何異常並將其放入調用線程中,我想要中斷鏈的工作。但我看到我的鏈條沒有損壞,並且act3act2也完成了。如何在發生異常時中斷任務鏈?

我該如何解決?

enter image description here

using System; 
using System.Threading.Tasks; 

namespace Bushman.Sandbox.Threads { 
    class Program { 
     static void Main(string[] args) { 
      Console.Title = "Custom thread"; 

      try { 
       // First work 
       Action act1 =() => { 
        for (int i = 0; i < 5; i++) { 

         // I throw the exeption here 
         if (i == 3) throw new Exception("Oops!!!"); 

         Console.WriteLine("Do first work"); 
        } 
       }; 

       // Second work 
       Action act2 =() => { 
        for (int i = 0; i < 5; i++) 
         Console.WriteLine(" Do second work"); 
       }; 

       // Third work 
       Func<int> act3 =() => { 
        for (int i = 0; i < 5; i++) 
         Console.WriteLine(" Do third work"); 
        return 12345; 
       }; 

       Task task = new Task(act1); 

       // Build the chain of the works 
       var awaiter = task.ContinueWith(_ => act2(), 
        TaskContinuationOptions.ExecuteSynchronously) 
        .ContinueWith(_ => act3(), 
        TaskContinuationOptions.ExecuteSynchronously) 
        .GetAwaiter(); 

       Console.WriteLine("Work started..."); 

       // launch the chain 
       task.Start(); 

       // Here I get some result 
       int result = awaiter.GetResult(); // 12345 

       if (task.IsCanceled || task.IsFaulted) { 
        throw task.Exception.InnerException; 
       } 

       Console.WriteLine("The result: {0}", 
        result.ToString()); 
      } 
      catch (Exception ex) { 
       Console.ForegroundColor = ConsoleColor.Red; 
       Console.WriteLine(ex.Message); 
       Console.ResetColor(); 
      } 

      Console.WriteLine("Press any key for exit..."); 
      Console.ReadKey(); 
     } 
    } 
} 
+1

爲什麼不直接使用'async/await'?你不需要'Task.Start'或直接訪問awaiter。此外,如果您想使用'ContinueWith',您*需要*訪問任務以檢查異常,例如 - 'ContinueWith(t => if(t.Faulted){..} else act3();)' –

+0

I學會通過一本書來處理線索\任務。我仍然沒有讀到'async/await'。 –

+1

我建議你查看關於如何正確使用的文檔示例,如ContinueWith和TasFactory.StartNew或Task.Run,​​如果你不想使用'async/await'。還要檢查Task.Result和Task.Wait()是做什麼的 - 它們會在任務出現故障時拋出。你的代碼太複雜了,並且試圖暴露實現內部結構,它只是不需要 –

回答

2

您必須使用NotOnFaulted任務延續選項。

由於TaskContinuationOptions裝飾有Flags屬性,因此可以將NotFaulted與其他選項結合使用。

var awaiter = task.ContinueWith(_ => act2(), 
       TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted) 
       .ContinueWith(_ => act3(), 
       TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnFaulted) 
       .GetAwaiter(); 

即使您正在使用異步/等待關鍵詞,這種方法仍然有效(但你擺脫GetAwaiter通話)

+0

謝謝。在這種情況下,「act2」沒有啓動,但「act3」仍然啓動。 –

+0

哦...如果我將TaskContinuationOptions.NotOnCanceled與TaskContinuationOptions.NotOnFaulted一起添加,那麼它就像我期望的那樣工作。謝謝! –

+0

嘗試AttachedToParent標誌。 –

2

代碼試圖以一種非常規使用任務方式,就好像它們是線程一樣。他們不是 - 任務是一個將被安排在線程池線程上運行的工作,而不是線程本身。調用Task.Start將不會執行任何操作,它會將時間表其委託在一個線程上運行。這就是爲什麼從不使用構造函數創建任務的原因。

啓動和協調任務最簡單的方法是使用Task.Run和async/await,如:

public static async Task<int> MyMethodAsync() 
{ 
    try 
    { 
     await Task.Run(()=>act1()); 
     await Task.Run(()=>act2()); 
     var result=await Task.Run(()=>act3()); 
     return result; 
    } 
    catch (Exception exc) 
    { 
      //Do something 
    } 
} 

你不能在一個控制檯應用程序的主要功能使用async/await,所以你必須調用通過以下方式方法:

var result=MyMethodAsync().Result; 

上調用任務.Wait().Result重新拋出它裏面提出的任何異常。

沒有async/await,您需要使用ContinueWith並實際檢查上一個任務的結果。如果你只是想停下來處理,你可以通過TaskContinuationOptions.NotOnFaulted:

var result = Task.Run(()=>act1()) 
       .ContinueWith(t1=>act2(),TaskContinuationOptions.NotOnFaulted) 
       .ContinueWith(t2=>act3(),TaskContinuationOptions.NotOnFaulted) 
       .Result; 

你並不需要去的awaiter明確的訪問。最後一次撥打.Result將返回整數結果,如果以前的某個任務出現故障,則返回AggregateException

+0

使用ContinueWith方法是「常規」的。我同意你的看法,異步/等待更清潔,更容易維護,但使用Start/GetAwaiter/GetResults沒有任何問題。最後,異步/等待只是這種方法的語法糖。 –

+0

@ MatteoMarciano-MSCP這些方法只對WinRT是必需的,WinRT沒有任務。沒有其他運行時需要它們。至於爲什麼使用它們是錯誤的,代碼的複雜性是顯而易見的。代碼結果更加複雜,沒有任何好處。唯一的地方,你會發現'Task.Start'在SO問題 –

+0

繼續仍然使用,仍然需要在某些情況下。關於WinRT不支持任務,這不完全正確。也許你在談論WinRT組件。 –

相關問題