TaskScheduler. Обработчик событий UnobservedTaskException, никогда не инициированный

Я прочитываю книгу о Библиотеке Параллели Задачи C# и имею следующий пример, но TaskScheduler. Обработчик UnobservedTaskException никогда не инициирован. Кто-либо может дать мне какой-либо ключ к разгадке относительно почему?

TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
{
    eventArgs.SetObserved();
    ((AggregateException)eventArgs.Exception).Handle(ex =>
    {
        Console.WriteLine("Exception type: {0}", ex.GetType());
        return true;
    });
};

Task task1 = new Task(() => 
{
    throw new ArgumentNullException();
});

Task task2 = new Task(() => {
    throw new ArgumentOutOfRangeException();
});

task1.Start();
task2.Start();

while (!task1.IsCompleted || !task2.IsCompleted)
{
    Thread.Sleep( 5000 );
}

Console.WriteLine("done");
Console.ReadLine();
34
задан Drew Noakes 23 September 2012 в 14:43
поделиться

2 ответа

К сожалению, этот пример никогда не покажет вам ваш код. Исключение UnobservedTaskException произойдет только в том случае, если задача будет собрана сборщиком мусора, при этом исключение не будет отслеживаться - пока вы сохраняете ссылку на задачу1 и задачу2 , сборщик мусора. никогда не будет собирать, и вы никогда не увидите свой обработчик исключений.

Чтобы увидеть поведение UnobservedTaskException в действии, я бы попробовал следующее (надуманный пример):

public static void Main()
{
    TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
                {
                    eventArgs.SetObserved();
                    ((AggregateException)eventArgs.Exception).Handle(ex =>
                    {
                        Console.WriteLine("Exception type: {0}", ex.GetType());
                        return true;
                    });
                };

    Task.Factory.StartNew(() =>
    {
        throw new ArgumentNullException();
    });

    Task.Factory.StartNew(() =>
    {
        throw new ArgumentOutOfRangeException();
    });


    Thread.Sleep(100);
    GC.Collect();
    GC.WaitForPendingFinalizers();

    Console.WriteLine("Done");
    Console.ReadKey();
}

Это покажет вам ваши сообщения. Первый вызов Thread.Sleep (100) предоставляет достаточно времени для выполнения задач. Сбор и ожидание заставляет сборщик мусора, который запускает ваш обработчик событий 2 раза.

53
ответ дан 27 November 2019 в 16:53
поделиться

Исключение не будет «незамеченным» в этом примере фрагмента. Только когда сборщик мусора избавится от экземпляров Task. Вам придется переписать его так:

class Program {
    static void Main(string[] args) {

        TaskScheduler.UnobservedTaskException += ( object sender, UnobservedTaskExceptionEventArgs eventArgs ) =>
        {
            eventArgs.SetObserved();
            ( (AggregateException)eventArgs.Exception ).Handle( ex =>
            {
                Console.WriteLine("Exception type: {0}", ex.GetType());
                return true;
            } );
        };

        Run();

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("done");
        Console.ReadLine();
    }

    static void Run() {
        Task task1 = new Task(() => {
            throw new ArgumentNullException();
        });

        Task task2 = new Task(() => {
            throw new ArgumentOutOfRangeException();
        });

        task1.Start();
        task2.Start();

        while (!task1.IsCompleted || !task2.IsCompleted) {
            Thread.Sleep(50);
        }
    }
}

Не делайте этого, используйте Task.Wait ().

4
ответ дан 27 November 2019 в 16:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: