Как вызвать AggregateException с TPL? - PullRequest
0 голосов
/ 22 декабря 2010

Я пытаюсь воссоздать условия, которые вызовут это исключение:

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

Я написал эту программу, думая, что вызову исключение, но это не так:

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

В моем реальном приложении я использую TPL, и я не кодировал свое право обработки исключений.В результате я получаю это исключение.Сейчас я пытаюсь воссоздать те же условия в отдельной программе, чтобы экспериментировать с ненаблюдаемыми исключениями.

Ответы [ 6 ]

4 голосов
/ 22 декабря 2010

Может потребоваться добавить вызов GC.WaitForPendingFinalizers () после GC.Collect (), поскольку финализаторы работают в своем собственном потоке.

3 голосов
/ 22 декабря 2010

Исключение выдается финализатором TaskExceptionHolder, поэтому поток финализатора должен быть запущен до появления этого исключения. Как указывает Джош, вы можете подождать, пока это произойдет, позвонив по номеру CG.WaitForPedingFinalizers().

Обратите внимание, что это поведение было изменено в текущей Async CTP. Я говорил со Стивеном Таубом из команды PFX об этом в TechEd Europe ранее в этом году, и он указал, что они должны были изменить его, чтобы новая асинхронная функциональность работала правильно. Так что пока еще рано говорить о следующей версии фреймворка, это поведение вполне может быть изменено в следующей версии.

1 голос
/ 14 января 2011

@ Хитрый, хотя вы пришли с рабочим ответом, я думаю, что большинству людей будет лучше, если прислушаться к сообщению об ошибке "... Ожидание задачи ..." Вовлечение в деятельность GC - это признак того, что вы либо близко знакомы с GC и имеете узкое место в производительности, либо упускаете суть. В моем случае это означает последнее;) Вызов StartNew возвращает Task, так почему бы не использовать его? например,

Task myTask = Task.Factory.StartNew (() => { бросить новое NullReferenceException ("ex"); }); // даем время для выполнения задачи
myTask.Wait ();

0 голосов
/ 28 марта 2012

Простейшим способом воссоздания ошибки является ожидание завершения задачи.

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

Ожидание вызова блокирует вызов до тех пор, пока задача не завершит выполнение.

0 голосов
/ 01 ноября 2011

Я действительно удивлен, что вы не пытались правильно вызвать код после завершения задачи, потому что кто сказал, что любой процесс завершится менее чем за 3 секунды?Не только это, но и то, что связывает другие процессы в течение полных 3 секунд.Я бы заменил эту реализацию методом задачи ContinueWith () для вызова GC после ее завершения.

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

Если вам требуется блокировка до ее завершения (для примера кода, который вы использовали для отладки),мог также сделать WaitOne после запуска задачи и иметь ContinueWith (), сигнализирующий обработчику ожидания.Если вам приходится делать это в своем производственном коде, то, возможно, то, что вы пытаетесь выполнить, на самом деле является синхронным, когда вам вообще не нужно беспокоиться об использовании задачи.

0 голосов
/ 10 января 2011

Я ОП. Я протестировал GC.WaitForPendingFinalizers (), но это не помогло воссоздать исключение. Проблема заключалась в том, что GC.Collect () был выполнен до запуска задачи.

Это правильный код для воссоздания исключения:

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