2017-05-18 20 views
3

複数のタスクのいずれかが失敗した場合は、再起動しようとしています。 Im HandleException(t)メソッドがexcistingタスクの配列内のタスクを見つけ、その代わりに新しいタスクを作成する.ContinueWith(t => { HandleException(t); }, TaskContinuationOptions.OnlyOnFaulted);を使用しています。私のHandleException(t)メソッドに渡されたタスクだけが元のタスクと異なり、私の無駄なタスクでそれを見つけることができません。例外が処理された時点で、excistingタスクも実行されています。で 失敗したタスクの再起動

using System; 
using System.Threading.Tasks; 
using System.Threading; 

static Task[] tasks; 
static void Main(string[] args) 
{ 
    tasks = new Task[2]; 
    for (int i = 0; i < tasks.Count(); i++) 
    { 
     tasks[i] = Task.Run(() => { Thread.Sleep(1000); throw new Exception("BOOM"); }) 
      .ContinueWith(t => { HandleException(t); } 
      , TaskContinuationOptions.OnlyOnFaulted); 

     Console.WriteLine(String.Format("Task {0} started", tasks[i].Id)); 
    } 

    Console.ReadLine(); 
} 

static void HandleException(Task task) 
{ 
    Console.WriteLine(String.Format("Task {0} stopped", task.Id)); 

    // Check task status 
    for (int i = 0; i < tasks.Count(); i++) 
    { 
     Console.WriteLine(String.Format("Task {0} status = {1}", i, tasks[i].Status)); 
    } 
    // fFind and restart the task here 
    if (tasks.Contains(task)) 
    { 
     int index = Array.IndexOf(tasks, task); 
     tasks[index] = Task.Run(() => { Thread.Sleep(1000); throw new Exception("BOOM"); }) 
     .ContinueWith(t => { HandleException(t); } 
     , TaskContinuationOptions.OnlyOnFaulted); 

     Console.WriteLine(String.Format("Task {0} started", tasks[index].Id)); 
    } 
} 

マイアプリケーションの結果:

Task 3 started 
Task 6 started 
Task 5 stopped 
Task 0 status = Running 
Task 2 stopped 
Task 1 status = Running 
Task 0 status = Running 
Task 1 status = Running 

HandleException(t)に渡されるタスクは、それがtasks[]したがってないで発見されていない、元のタスクとは異なるので、再開されました。また、tasks[]の状態を見ると、まだ停止していません。タスクを正しく再開するにはどうすればよいですか?

答えて

4

これは、継続タスクをオリジナルのタスクではなくアレイに保存しているからです(つまり、結果はContinueWithです)。修正するには、代わりに元のタスクを保存してください。

var task = Task.Run(() => { Thread.Sleep(1000); throw new Exception("BOOM");}); 
task.ContinueWith(t => { HandleException(t); } 
     , TaskContinuationOptions.OnlyOnFaulted); 
tasks[i] = task; 
+0

これは確かに問題でした。また、タスクのステータスも修正されました。 – MrEighteen

+0

@Evk HandleException(t)は再帰呼び出しなので、最終的にはスタックオーバーフローが導入されませんか? –

+1

@MaximPodkolzinいいえ、すべてが別のスレッドで発生するためです。新しいタスクは 'Task.Run'で開始され、これはスレッドプールからスレッドを取得します>例外がスローされます> HandleExceptionは別のスレッドで再度呼び出されます>' Task.Run'が再度呼び出され、別のスレッドがスレッドプールから取得されますHandleExceptionの実行中にビジー状態になっているため使用できません)>現在のスレッドは実行を終了してプールに戻ります。スタックオーバーフローの場合、同じスレッドが関数を再帰的に実行する必要がありますが、ここでは異なるスレッド(および異なるスタック)があります。 – Evk

関連する問題