Вопрос

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

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, и я не кодировал свою обработку исключений правильно. В результате я получаю это исключение. Теперь я пытаюсь воссоздать те же условия в отдельной программе, чтобы экспериментировать с ненаблюдаемыми исключениями.

Это было полезно?

Решение 5

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

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

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

Другие советы

Возможно, вам придется добавить звонок в GC.WaitForpendingFinalizers () после gc.collect (), поскольку финализаторы работают в их собственном потоке.

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

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

@Sly, хотя вы придумали рабочий ответ, я думаю, что большинству людей будет лучше обслуживать предложение об ошибке «... ожидая задачи ...». Привлечение к активности GC является признаком того, что вы знаете GC глубоко и имеете узкое место в производительности, либо вам не хватает. В моем случае это означает последний;) Вызов Startnew действительно возвращает задачу, так почему бы не использовать ее? например

Задача mytask = task.factory.startnew (() => {бросить новый nullreferenceexception ("ex");}); // Дайте некоторое время выполнению задачи
mytask.wait ();

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

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

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

Самый простой способ воссоздания ошибки - это ожидание задачи.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top