Exceptions silencieuses dans Task.Factory.StartNew lors de l’utilisation d’une tâche de consommateur d’arrière-plan de longue durée?

Cela signale une exception non gérée:

new Thread(_ => { throw new Exception(); }).Start(); 

Cela ne veut pas (au moins jusqu’à ce que vous attendez / récupérez le résultat):

 Task.Factory.StartNew(() => { throw new Exception(); }); 

Pourquoi? Qu’est-il arrivé au fil sur lequel l’exception a été lancée? Meurt-il?

C’est un problème où vous exécutez une tâche sans avoir besoin de son résultat, ni besoin de l’attendre, comme ceci:

 _operationQueue = new BlockingCollection(); Task.Factory.StartNew(() => { foreach (var item in _operationQueue.GetConsumingEnumerable()) { // do something that throws } }, TaskCreationOptions.LongRunning); 

Dans ce cas, dans quel état la _operationQueue est- _operationQueue laissée?

Je sais que je peux utiliser une continuation avec TaskContinuationOptions.OnlyOnFaulted, pouvez-vous simplement reprendre le traitement?

Eh bien, que présumez-vous que cela devrait arriver à la place? Pensez-vous que chaque fois qu’une exception est levée dans un autre thread, elle devrait se propager immédiatement au thread qui a démarré cette tâche? Je suis fortement en désaccord. Tout d’abord, le code dans le thread appelant serait alors obligé d’abandonner l’opération en cours, ce qui risquerait fort de causer des problèmes importants. Il suffit de regarder dans tous les articles entourant Thread.Abort pour voir tous les problèmes très importants qui se posent lorsque vous permettez qu’une exception soit renvoyée à un moment quelconque de l’exécution d’un programme plutôt qu’à certains points connus.

Si vous suggérez que tout le programme devrait planter quand le code d’une tâche lève une exception, alors je dirais que dans l’ensemble, ce n’est tout simplement pas souhaitable. Dans les rares cas où cela se produit, vous pouvez (assez facilement) créer une continuation sur la tâche qui met fin au processus complet si la tâche est défaillante. Je n’ai toutefois pas encore besoin de créer une telle continuation moi-même. Si le système était conçu pour interrompre le processus lorsqu’une tâche lançait une exception, il ne serait pas aussi facile d’obtenir le comportement opposé.

Qu’est-il arrivé au fil sur lequel l’exception a été lancée? Meurt-il?

Si l’exception est interceptée, l’exécution se poursuit après l’interception; si elle se propage à travers toute la stack d’appels, l’exception sera interceptée par le code dans le cadre de la Task , qui enveloppe l’exception et la met à la disposition des suites.

Dans ce cas, dans quel état la _operationQueue est-elle laissée?

C’est une file d’attente tout à fait correcte, qui a été supprimée des éléments 1..N. Si le corps de la boucle lance toujours, alors un élément aura été pris. Si cela ne se produit que de temps en temps, un certain nombre d’articles lui seront retirés. Les éléments restants sont toujours dans la queue et peuvent être supprimés par tout autre thread ayant access à celle-ci. Si la queue n’est plus accessible, elle deviendrait éligible pour la récupération de place.

Je sais que je peux utiliser une continuation avec TaskContinuationOptions.OnlyOnFaulted, pouvez-vous simplement reprendre le traitement?

Le fil d’appel peut; sûr. La tâche elle-même ne pourrait continuer que si un délégué try/catch . Si l’exception a été levée au point que la tâche est défaillante, rien ne permettra à cette tâche de continuer à s’exécuter.

L’exception dans la tâche est interceptée par TaskScheduler . Si vous ne souhaitez jamais observer le résultat d’une tâche, mais souhaitez être averti des exceptions non TaskScheduler.UnobservedTaskException dans les tâches, il existe l’événement TaskScheduler.UnobservedTaskException . Notez que cet événement ne se déclenche pas immédiatement, mais lors de la finalisation de la Task si l’exception n’a jamais été récupérée. Dans .Net 4, les exceptions de tâches non observées ont été modifiées et sont devenues des exceptions non gérées qui ont mis fin au processus, mais cela a été modifié dans .Net 4.5.