2010-11-18 7 views
20

J'ai un problème avec la gestion des exceptions et les tâches parallèles.Task.WaitAll et exceptions

Le code ci-dessous commence 2 tâches et attend qu'elles se terminent. Mon problème est que, dans le cas où une tâche jette une exception, le gestionnaire de catch n'est jamais atteint. Toutefois, lorsque j'utilise le code suivant pour attendre les tâches avec un délai d'attente, l'exception est interceptée.

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

je semble manquer quelque chose, comme la documentation WaitAll décrit ma première tentative d'être le bon. Aidez-moi à comprendre pourquoi cela ne fonctionne pas.

+1

Que font TaskMethod1 et TaskMethod2? Sur quel fil exécutez-vous? Si vous pouviez transformer cela en un exemple court mais complet (comme ma réponse), cela aiderait vraiment. –

Répondre

21

Impossible de reproduire cela - cela fonctionne bien pour moi:

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"); 
     } 
    } 
} 

qui imprime « Quelque chose a mal tourné », tout comme je pense.

Est-il possible qu'une de vos tâches ne soit pas terminée? WaitAll attend vraiment que toutes les tâches soient terminées, même si certaines ont déjà échoué.

+2

merci pour votre réponse rapide Jon! Mon problème était/est que l'autre tâche dépend de la tâche échouée, donc il attendrait toujours sur la tâche échouée. Mon idée était, que l'exception est attrapée immédiatement lorsqu'une tâche échoue, ce qui n'est pas le cas. Merci d'avoir fait remarquer cela. – thumbmunkeys

+5

@pivotnig - jetez un coup d'œil à la section 'Création de tâches continues' ici pour exprimer la dépendance explicitement - http://msdn.microsoft.com/fr-fr/library/dd537609.aspx –

+0

@thumbmunkeys ne s'est pas rendu compte que ceci a posté cela. C'est exactement ce que j'ai demandé ici: https://stackoverflow.com/q/47820918/695964 – KFL

9

Voilà comment je résolu le problème, comme évoqué dans les commentaires sur ma réponse/question (ci-dessus):

L'appelant attire toutes les exceptions soulevées par les tâches coordonné par la barrière, et les signaux des autres tâches avec une annulation forcée:

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

C'est sympa. Je n'ai jamais réalisé ce cas d'utilisation pour 'CancellationTokenSource'. – trailmax

0

je tentais de créer un appel pour chaque élément dans une collection, qui se révéla quelque chose comme ceci:

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); 
    } 
    }); 

Je devais ajouter le Thread.Sleep après chaque ajout d'une tâche enfant car sinon, le processus aurait tendance à écraser le currAcctNo avec l'itération suivante. J'aurais 3 ou 4 numéros de compte distincts dans ma liste, et quand il traiterait chacun, l'appel ProcessThisAccount afficherait le dernier numéro de compte pour tous les appels. Une fois que j'ai mis le sommeil, le processus fonctionne très bien.

+0

qui pourrait être d'intérêt: http://stackoverflow.com/questions/5009181/parallel-foreach-vs-task-factory-startnew – thumbmunkeys

+0

Parallel.ForEach plus efficace? – Kiquenet

+0

qu'est-ce que cette réponse a à voir avec la question d'origine? aucune exception ici – knocte