Pregunta

Estoy tratando de recrear las condiciones que harán que esta excepción:

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.`

Me escribió este programa pensando que me causo la excepción pero no:

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

En mi aplicación real, yo uso TPL y no CÓDIGO Mi gestión de excepciones derecha. Como resultado de ello consigo que la excepción. Ahora estoy tratando de recrear las mismas condiciones en un programa separado para experimentar con las excepciones observadas.

¿Fue útil?

Solución 5

Soy el OP. Probé los GC.WaitForPendingFinalizers (), pero no sirvió de nada recrear la excepción. El problema era que el GC.Collect () se ejecuta antes de que inicie la tarea.

Este es el código correcto para recrear la excepción:

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

Otros consejos

Es posible que necesite añadir una llamada a GC.WaitForPendingFinalizers () después de GC.Collect (), ya que los finalizadores se ejecutan en su propio hilo.

La excepción es lanzada por el finalizador de TaskExceptionHolder, por lo que el subproceso finalizador debe ejecutar antes de esta excepción. Como señala Josh, se puede esperar a que esto suceda llamando CG.WaitForPedingFinalizers().

Tenga en cuenta que este comportamiento se ha cambiado en la corriente asíncrono CTP. Hablé con Stephen Toub del equipo PFX sobre esto en TechEd Europa a principios de este año, e indicó que tenían que cambiarla por la nueva funcionalidad asíncrono para que funcione correctamente. Así, mientras que todavía es demasiado pronto para decir nada acerca de la próxima versión del marco, este comportamiento podría muy bien ser cambiado en la próxima versión.

@Sly, a pesar de que se le ocurrió una respuesta de trabajo, creo que la mayoría de la gente sería mejor servido por hacer caso a la sugerencia mensaje de error "... en espera en la tarea ...". La participación en la actividad de GC es una señal de que cualquiera sabe íntimamente GC y tienen un cuello de botella o que se está perdiendo el punto. En mi caso, significa que la última;) La llamada StartNew hace volver una tarea así que por qué no usarlo? por ejemplo.

Tarea MyTask = Task.Factory.StartNew (() => { arrojar nueva NullReferenceException ( "ex"); }); // dar un poco de tiempo para la tarea que completa
myTask.Wait ();

Estoy realmente sorprendido de que no haya intención de codificar adecuadamente llamada después de la finalización de tareas, porque ¿quién puede decir que todo proceso se completará menos de 3 segundos? No sólo eso, sino que los lazos hasta otros procesos para un total de 3 segundos. Me gustaría sustituir a la aplicación con el método tarea ContinueWith () para llamar a la GC después de que se complete la tarea.

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

Si necesita bloquear hasta que sea completa (por ejemplo, el código que estaba utilizando para depurar), también se puede hacer un WaitOne después de comenzar la tarea y tienen ContinueWith () una señal al controlador de espera. Si va a tener que hacer esto en su código de producción, entonces tal vez lo que estamos tratando de lograr es en realidad sincrónica en la que no tiene que preocuparse acerca de cómo utilizar una tarea en absoluto.

La forma más sencilla para recrear el error está esperando a que la tarea completa.

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

Llamada espera bloqueará la llamada hasta que la tarea tiene la ejecución final.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top