C # Бросить OperationCanceledException изнутри CancellationToken.Register

2

У меня длительная операция, которую я хочу отменить, скажем, через 5 секунд. К сожалению, опрос для IsCancellationRequested невозможен (длинная история).

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

Похоже, что это не работает должным образом, так как это приводит к необработанному исключению, и приложение не завершается корректно.

Любая помощь приветствуется. Спасибо!

    void TestTimeOut()
    {
        var cts = new CancellationTokenSource();
        cts.CancelAfter(5000);

        try
        {
            var task = Task.Run(() => LongRunningOperation(cts.Token));
            task.ContinueWith(t => Console.WriteLine("Operation cancelled"), TaskContinuationOptions.OnlyOnFaulted);
            task.Wait();
        }
        catch (AggregateException e)
        {
            //Handle
        }
    }


    void LongRunningOperation(CancellationToken token)
    {
        CancellationTokenRegistration registration = token.Register(
            () =>
            {
                throw new OperationCanceledException(token); 
            });

        using (registration)
        {
            // long running operation here
        }
    }
  • 1
    Какой смысл запускать что-то в задаче, если вы .Wait() это? Использование CancellationToken является кооперативным. Может быть, вы можете просто создать поток, если вы на самом деле не используете асинхронные функции (ключевое слово await).
  • 0
    @DennisKuypers После Task.Wait () нужно выполнить другие действия, но только если долгосрочное задание завершено. В противном случае я хотел бы поймать отмененное исключение, сделать несколько уборок и выйти из приложения.
Показать ещё 3 комментария
Теги:
multithreading
cancellation

2 ответа

0

В вашем коде много No-No-es, но я думаю, вы просто используете его в качестве демонстрации для своей проблемы. TaskCompletionSource является TaskCompletionSource, моя демка тоже ужасна, слишком много слоев Task.Run(), если вы используете Async, вы должны выполнить асинхронизацию до конца. Так что не используйте его в PRD, изучите TaskCompletionSource самостоятельно и TaskCompletionSource лучшее решение.

    static void LongRunningOperation(CancellationToken token)
    {
        TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
        token.Register(() => { tcs1.TrySetCanceled(token); });
        Task.Run(() =>
        {
            // long running operation here
            Thread.Sleep(10000);
            tcs1.TrySetResult(0);
        }, token);
        tcs1.Task.Wait();
    }
0

Вы перехватываете AggregateException но фактически создаете исключение OperationCanceledException которое не будет перехвачено.

Изменить, чтобы поймать все типы исключений, таких как

catch (Exception ex) { ... }

Разрешить.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню