2010-11-18 12 views
20

że problem z obsługi wyjątków i zadania równolegle.Task.WaitAll i wyjątkami

Kod pokazany poniżej rozpoczyna 2 zadania i czeka na nich do końca. Mój problem polega na tym, że w przypadku, gdy zadanie zgłasza wyjątek, program obsługi catch nigdy nie zostanie osiągnięty.

 List<Task> tasks = new List<Task>(); 
     try 
     {     
      tasks.Add(Task.Factory.StartNew(TaskMethod1)); 
      tasks.Add(Task.Factory.StartNew(TaskMethod2)); 

      var arr = tasks.ToArray();     
      Task.WaitAll(arr); 
     } 
     catch (AggregateException e) 
     { 
      // do something 
     } 

Jednak kiedy użyć następującego kodu czekać do zadań z timeout, wyjątek zostanie złapany.

while(!Task.WaitAll(arr,100)); 

I wydaje się, że brakuje czegoś, jako dokumentacja dla WaitAll opisuje moją pierwszą próbę być prawidłowa. Pomóż mi zrozumieć, dlaczego to nie działa.

+1

Czego TaskMethod1 i TaskMethod2 zrobić? W jakim wątku jesteś wykonywany? Jeśli mógłbyś zamienić to w krótki, ale * kompletny * przykład (jak moja odpowiedź), który by naprawdę pomógł. –

Odpowiedz

21

nie można odtworzyć tego - to działa dobrze dla mnie:

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

class Test 
{ 
    static void Main() 
    { 
     Task t1 = Task.Factory.StartNew(() => Thread.Sleep(1000)); 
     Task t2 = Task.Factory.StartNew(() => { 
      Thread.Sleep(500); 
      throw new Exception("Oops"); 
     }); 

     try 
     { 
      Task.WaitAll(t1, t2); 
      Console.WriteLine("All done"); 
     } 
     catch (AggregateException) 
     { 
      Console.WriteLine("Something went wrong"); 
     } 
    } 
} 

która drukuje „Coś poszło nie tak”, tak jak ja się spodziewać.

Czy to możliwe, że jedno z zadań nie jest gotowy? WaitAll naprawdę czeka na zakończenie wszystkich zadań, nawet jeśli niektóre z nich już się nie powiodły.

+2

dzięki za szybką odpowiedź Jon! Moim problemem było/jest to, że inne zadanie zależy od nieudanego zadania, dlatego będzie czekać na zawsze na nieudane zadanie. Mój pomysł był taki, że wyjątek jest wychwytywany natychmiast, gdy zadanie się nie powiedzie, co nie jest prawdą. dzięki za wskazanie tego. – thumbmunkeys

+5

@pivotnig - spojrzeć na „Tworzenie zadań kontynuacje”, żeby wyrazić zależność wprost - http://msdn.microsoft.com/en-us/library/dd537609.aspx –

+0

@thumbmunkeys nie zdawał sobie sprawy, to pisał to. To jest dokładnie to, co ja zapytałem tutaj: https://stackoverflow.com/q/47820918/695964 – KFL

9

Oto jak rozwiązać ten problem, jak wspomniałem w komentarzach na moją odpowiedź/pytanie (powyżej):

Dzwoniący łapie wszystkie wyjątki zgłaszane przez zadania koordynowane przez barierę i sygnalizuje inne zadania z wymuszonym rezerwacji:

CancellationTokenSource cancelSignal = new CancellationTokenSource(); 
try 
{ 
    // do work 
    List<Task> workerTasks = new List<Task>(); 
    foreach (Worker w in someArray) 
    { 
     workerTasks.Add(w.DoAsyncWork(cancelSignal.Token); 
    } 
    while (!Task.WaitAll(workerTasks.ToArray(), 100, cancelSignal.Token)) ; 

} 
catch (Exception) 
{ 
    cancelSignal.Cancel(); 
    throw; 
} 
+1

To jest miłe. Nigdy nie zdałem sobie sprawy z tego przypadku użycia dla 'CancellationTokenSource'. – trailmax

0

starałem się tworzyć połączenia dla każdego elementu w kolekcji, która okazała się mniej więcej tak:

var parent = Task.Factory.StartNew(() => { 
    foreach (var acct in AccountList) 
    { 
     var currAcctNo = acct.Number; 
     Task.Factory.StartNew(() => 
     { 
     MyLocalList.AddRange(ProcessThisAccount(currAcctNo)); 
     }, TaskCreationOptions.AttachedToParent); 
     Thread.Sleep(50); 
    } 
    }); 

Musiałem dodać Thread.leep po każdym dodaniu zadania potomnego, ponieważ gdybym tego nie zrobił, proces ten nadpisałby currAcctNo kolejną iteracją. Na liście mam 3 lub 4 odrębne numery kont, a po przetworzeniu każdego, wywołanie ProcessThisAccount wyświetli ostatni numer konta dla wszystkich połączeń. Po umieszczeniu Sleep, proces działa świetnie.

+0

, które mogą być interesujące: http://stackoverflow.com/questions/5009181/parallel-foreach-vs-tas-task-factory-startnew – thumbmunkeys

+0

Parallel.ForEach bardziej wydajne? – Kiquenet

+0

co ta odpowiedź ma wspólnego z pierwotnym pytaniem? bez wyjątków tutaj – knocte

Powiązane problemy