2017-01-10 6 views
-2

私は作品のチェーンを作成します。彼らは私の追加のスレッドの内部で作業する必要があります。私はこの目的のためにTaskを使用します。また、例外が発生した場合にチェーンの作業を中断し、呼び出しスレッドにスローしたいと思います。しかし、チェーンが壊れていないことがわかりました。act2act3も完成しました。例外が発生したときにタスクチェーンを壊す方法はありますか?

どうすれば修正できますか?あなたはNotOnFaultedタスク継続オプションを使用する必要が

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'や待ち時間のいずれかに直接アクセスする必要はありません。さらに、 'ContinueWith'を使用して、例外をチェックするためのタスクへのアクセスが必要な場合 - 例えば' ContinueWith(t => if(t.Faulted){..} else act3();) ' –

+0

I本を介してthreads \ tasksで作業する方法を学ぶ。私はまだ 'async/await'については読まなかった。 –

+1

'async/await'を使用したくない場合は、ContinueWithやTasFactory.StartNewやTask.Runなどを正しく使用する方法のドキュメント例を確認することをお勧めします。また、Task.ResultとTask.Wait()が何をしているかを確認します。タスクにフォールトが発生した場合にthrowします。あなたのコードははるかに複雑で、必要のない実装の内部を公開しようとします –

答えて

2

TaskContinuationOptionsはFlags属性で修飾されているため、NotFaultedと他のオプションを組み合わせることができます。

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

あなたが/キーワードを待つ非同期を使用している場合でも、このアプローチがまだ有効である(しかし、あなたはGetAwaiterコールを取り除く)

+0

ありがとう。この場合、 'act2'は起動されませんでしたが、' act3'はまだ起動されました。 –

+0

Oh ... '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への最後の呼び出しは、整数結果を返すか、以前のタスクの1つが失敗した場合にはAggregateExceptionを投げるでしょう。

+0

ContinueWithメソッドの使用は「従来型」です。 async/awaitはよりクリーンでメンテナンスが簡単ですが、Start/GetAwaiter/GetResultsを使用するのは間違いありません。結局のところ、async/awaitはそのようなメソッドに対する構文的な砂糖に過ぎません。 –

+0

@ MatteoMarciano-MSCPこれらのメソッドは、タスクを持たないWinRTでのみ必要でした。それ以外のランタイムは必要ありません。なぜそれらを使うのが間違っているのかというと、コードの複雑さは明らかです。コードは、何の利益もないほど複雑になります。 'Task.Start'がSOの質問にある唯一の場所 –

+0

継続は依然として使われており、状況によってはまだ必要です。タスクをサポートしていないWinRTについては、それは完全に真実ではありません。たぶん、あなたはWinRTコンポーネントについて話しているのかもしれません。 –

関連する問題