Question

Disons que j'ai trois tâches, a, b, et c.Tous les trois sont assurés de lancer une exception à un moment aléatoire compris entre 1 et 5 secondes.J'écris ensuite le code suivant :

await Task.WhenAny(a, b, c);

Cela finira par générer une exception à la tâche qui échouera en premier.Puisqu'il n'y a pas try...catch ici, cette exception remontera à un autre endroit dans mon code.

Que se passe-t-il lorsque les deux tâches restantes lèvent une exception ?Ne s’agit-il pas d’exceptions inobservées, qui entraîneront la mort de l’ensemble du processus ?Cela signifie-t-il que la seule façon d'utiliser WhenAny est à l'intérieur d'un try...catch bloquer, puis observer d'une manière ou d'une autre les deux tâches restantes avant de continuer ?

Suivi: J'aimerais que la réponse s'applique aux deux à .NET 4.5 et .NET 4.0 avec le pack de ciblage asynchrone (bien qu'utilisant clairement TaskEx.WhenAny dans ce cas).

Était-ce utile?

La solution

Que se passe-t-il lorsque les deux tâches restantes lèvent une exception ?

Ceux Tasks se terminera dans un état défectueux.

Ne s’agit-il pas d’exceptions inobservées, qui entraîneront la mort de l’ensemble du processus ?

Pas plus.

Dans .NET 4.0, le Task le destructeur transmettrait son exception non observée à TaskScheduler.UnobservedTaskException, ce qui mettrait fin au processus s'il n'était pas géré.

Dans .NET 4.5, ceci le comportement a été modifié.Désormais, les exceptions non observées sont transmises à TaskScheduler.UnobservedTaskException, mais ils sont ensuite ignorés s'ils ne sont pas gérés.

Autres conseils

Oui, les exceptions de tâches restantes ne sont pas observées.Avant .NET 4.5, vous êtes obligé de les respecter (je ne sais pas comment est la situation sur .NET 4.5, mais elle a changé).

J'écris habituellement moi-même une méthode d'assistance pour les tâches de type « déclencher et oublier » comme celles-ci :

    public static void IgnoreUnobservedExceptions(this Task task)
    {
        if (task.IsCompleted)
        {
            if (task.IsFaulted)
            {
                var dummy = task.Exception;
            }
            return;
        }

        task.ContinueWith(t =>
            {
                var dummy = t.Exception;
            }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
    }

Vous souhaiterez peut-être inclure la connexion dans les applications de production.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top