Question

Je suis en train de recréer les conditions qui causeront cette exception:

System.AggregateException: A Task's exception(s) were not observed 
either by Waiting on the Task or accessing its Exception property. 
As a result, the unobserved exception was rethrown by the finalizer thread.`

J'ai écrit ce programme en pensant que je fais l'exception, mais il ne le fait pas:

using System;
using System.Threading.Tasks;
namespace SomeAsyncStuff
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); });
            GC.Collect();
            Console.WriteLine("completed");            
        }
    }
}

Dans mon application réelle, j'utilise TPL et je ne pas de code mon droit de gestion des exceptions. En conséquence, je reçois cette exception. Maintenant, je suis en train de recréer les mêmes conditions dans un programme distinct pour expérimenter des exceptions non observées.

Était-ce utile?

La solution 5

Je suis l'OP. Je l'ai testé les GC.WaitForPendingFinalizers (), mais il n'a pas aidé à recréer l'exception. Le problème était que la GC.Collect () a été exécuté avant que la tâche a commencé.

Ceci est le code correct pour recréer l'exception:

using System;
using System.Threading;
using System.Threading.Tasks;
namespace SomeAsyncStuff
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); });

            // give some time to the task to complete
            Thread.Sleep(3000);

            GC.Collect();
            // GC.WaitForPendingFinalizers();
            Console.WriteLine("completed"); 
        }
    }
}

Autres conseils

Vous devrez peut-être ajouter un appel à GC.WaitForPendingFinalizers () après GC.Collect () depuis finalizers courir sur leur propre fil.

L'exception est levée par finaliseur TaskExceptionHolder, de sorte que le thread finaliseur doit exécuter avant cette exception est levée. Comme Josh souligne, vous pouvez attendre que cela se produise en appelant CG.WaitForPedingFinalizers().

S'il vous plaît avis que ce comportement a été modifié dans le Async CTP en cours. J'ai parlé à Stephen Toub de l'équipe PFX à ce sujet à TechEd Europe plus tôt cette année, et il a indiqué qu'ils devaient changer pour la nouvelle fonctionnalité de async pour fonctionner correctement. Ainsi, alors qu'il est encore trop tôt pour dire quoi que ce soit au sujet de la prochaine version du cadre, ce comportement pourrait très bien être modifié dans la prochaine version.

@Sly, bien que vous êtes venu avec une réponse de travail, je pense que la plupart des gens seraient mieux servis en prêtant attention à la suggestion de message d'erreur « ... En attente sur la tâche ... ». Participer à l'activité GC est un signe que ce soit que vous connaissez intimement GC et un goulot d'étranglement ou vous manque le point. Dans mon cas, cela signifie que celui-ci;) L'appel StartNew fait retourner une tâche alors pourquoi ne pas l'utiliser? par exemple.

Groupe MyTask = Task.Factory.StartNew (() =>         {             throw new NullReferenceException ( "ex");         }); // donner un peu de temps à la tâche à accomplir
        myTask.Wait ();

Je suis vraiment surpris que vous n'avez pas tenté de coder correctement appel après l'exécution des tâches, car qui peut dire que tout processus achèvera moins de 3 secondes? Non seulement cela, mais que des liens vers le haut d'autres processus pour 3 secondes une. Je remplacerais que la mise en œuvre par la méthode de la tâche ContinueWith () pour appeler le GC après la finalise la tâche.

Task.Factory
    .StartNew(() => { throw new NullReferenceException("ex"); })
    .ContinueWith(p => GC.Collect());

Si vous avez besoin de bloquer jusqu'à ce qu'il soit complet (pour votre exemple de code que vous utilisez pour le débogage), vous pouvez aussi faire un WaitOne après avoir commencé la tâche et ont ContinueWith () signaler le gestionnaire d'attente. Si vous êtes d'avoir à le faire dans votre code de production alors peut-être ce que vous essayez d'accomplir est réellement synchrone où vous n'avez pas à vous soucier de l'aide d'une tâche à tous.

La façon la plus simple de recréer l'erreur est en attente de la tâche à accomplir.

Task task = Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); });
//this is where the exception will be thrown
task.Wait();

L'appel attente bloque l'appel jusqu'à ce que la tâche a l'exécution terminée.

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