Отмена выбрасывания необработанного исключения в .Net - PullRequest
0 голосов
/ 05 мая 2018

Кажется, это общая проблема, но я пока не могу найти решение. Я проверил это в SO Отмена задания вызывает исключение

Мой абонент:

    Private Async Sub btnTestTimer_Click(sender As Object, e As EventArgs) Handles btnTest.Click
    _cts = New CancellationTokenSource()
    Try
        Await Task.Run(AddressOf TestCancellationAsync).ConfigureAwait(False)
    Catch cx As OperationCanceledException
        MsgBox(String.Format("The following error occurred: {0}", cx.Message), MsgBoxStyle.Critical)
    Catch ex As Exception
        MsgBox(String.Format("The following error occurred: {0}", ex.Message), MsgBoxStyle.Critical)
    End Try
End Sub

Моя задача здесь

    Private Async Function TestCancellationAsync() As Task
        'Launch a dummy timer which after some time will itself cancel a token and throw
        Dim tmr As New System.Timers.Timer(1000)
        AddHandler tmr.Elapsed, AddressOf OnTimerElapsed
        tmr.Enabled = True
    End Function

И функция таймера, которая отменяет и выбрасывает, является

    Private Sub OnTimerElapsed(sender As Object, e As ElapsedEventArgs)
        Dim tmr As System.Timers.Timer = CType(sender, System.Timers.Timer)
        tmr.Enabled = False
        Task.Delay(5000) 'After 5 seconds simulate a cancellation
        _cts.Cancel() //This is just to cancel from within the timer, actually the cancellation to _cts will happen from another caller which is not shown here
        _cts.Token.ThrowIfCancellationRequested()
    End Sub

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

Бизнес-требование заключается в том, что при нажатии кнопки запускается асинхронная задача, которая открывает несколько асинхронных функций. Один из них запускает таймер, который будет проверять состояние токена _cts и отменять его при необходимости. Если такая отмена происходит извне на токене _cts, таймер сгенерирует исключение отмены

Вещи, которые я пробовал:

  • Я обработал исключение OperationCancelled, но оно по-прежнему не выполняется.
  • У меня снят флажок Tools-Options-Debug-General-Enable, только мой код, чтобы увидеть, является ли он Visual Studio. Но все же это сообщается как необработанное исключение PDB
  • Я запустил exe извне, как и ожидалось, он завис из-за необработанного исключения

Дайте мне знать, что я здесь делаю неправильно. Мой вызывающий ожидает завершения задачи - так как таймер запускается изнутри задачи, я буду ожидать, что задача не завершена, и любые возникшие исключения будут обнаружены.

1 Ответ

0 голосов
/ 05 мая 2018

Я думаю, что в этом случае проблема была в таймере. Создание и наличие таймера для запуска из задачи, а затем для исключения исключения отмены из метода обработки таймера не работает, поскольку, как только таймер создан и включен, задача возвращается без ожидания завершения таймера. Это означает, что метод TestCancellationAsync не ожидает запуска кода таймера и удерживает задачу. Он немедленно возвращается к звонящему. Вызывающий объект внутри btnTestTimer_Click считает, что задание вернулось, выходит из попытки и завершает метод. Это означает, что нет допустимых обработчиков событий, чтобы перехватить исключение, выданное таймером. Это приводит к необработанному исключению.

Решение состоит в том, чтобы симулировать таймер, используя бесконечный цикл с соответствующими задержками и вызывая код таймера из него без создания объекта таймера.

Таким образом, TestCancellationAsync следует изменить, чтобы он выглядел следующим образом

    Private Async Function TestCancellationAsync() As Task
    'Simulate a timer behaviour
    While True
        Await DoWorkAsync().ConfigureAwait(False)
        Await Task.Delay(1000).ConfigureAwait(False)
    End While
End Function

И OnTimerElapsed, который фактически является рабочей функцией, можно затем изменить на

Private Async Function DoWorkAsync() As Task
    'Do work code
    _cts.Token.ThrowIfCancellationRequested()
End Sub

Теперь, если _cts отменяется извне, его ловят.

Это решает текущую проблему.

...