Почему состояние этой задачи RanToCompletion, хотя я ее отменил?

В следующем фрагменте кода у меня есть задача, которая отменяется, когда пользователь нажимает любую клавишу. При этом вызывается ContinuationTask с сообщением об отмене задачи. ContinuationTask настроен так, что он запускается только при отмене задачи — и это действительно так.

Но когда я проверяю статус задачи после завершения в вызывающем потоке, я получаю «RanToCompletion». Как это возможно?

Вот код:

private static void ContinuationForCanceledTask()
{
    CancellationTokenSource tokenSource = new CancellationTokenSource();

    CancellationToken token = tokenSource.Token;

    Task t = Task.Run(
        () =>
        {
            while (!token.IsCancellationRequested)
            {
                Console.WriteLine("Nelson: Haha! - I am still running!!");

                Thread.Sleep(1000);
            }

            token.ThrowIfCancellationRequested();
        }, token);

    //This continuation task is invoked as expected
    t.ContinueWith(
        (tawsk) =>
        {
            Console.WriteLine("Tawsk was canceled");
        }
        , TaskContinuationOptions.OnlyOnCanceled);

    Console.WriteLine("Press any key to stop Nelson from laughing at you...");

    Console.ReadKey();

    tokenSource.Cancel();

    t.Wait();

    //Returns "RanToCompletion"
    Console.WriteLine("State of the Task is {0}", t.Status);
}

person FunkyPeanut    schedule 24.12.2014    source источник
comment
вы должны добавить try-catch в t.Wait();, иначе ваша программа завершится с необработанным исключением.   -  person kennyzx    schedule 24.12.2014
comment
Не могли бы вы проверить, что это воспроизводится каждый раз? Во-вторых, проверьте, что token.ThrowIfCancellationRequested() попал или нет.   -  person dotnetstep    schedule 24.12.2014
comment
Похоже, что вызов ThrowIfCancellationRequested() находится вне цикла и не будет выполнен до тех пор, пока задача не выполнит свои основные обязанности.   -  person Nathan Tuggy    schedule 24.12.2014
comment
@NathanTuggy не существует такого понятия, как основные обязанности задачи, задача выполнялась до завершения, если ни исключение, ни отмена никогда не возникали, и статус задачи устанавливается после того, как возникает отмена, а не после основные обязанности, если вы имеете в виду цикл while.   -  person kennyzx    schedule 24.12.2014
comment
@kennyzx: хм, нет, ты прав, состояние while должно быть достаточно хорошим. Тем более загадочно.   -  person Nathan Tuggy    schedule 24.12.2014
comment
@kennyzx Спасибо за это. На самом деле я получил свой подход выше из книги, в которой говорится, что вместо перехвата исключения вы можете добавить задачу продолжения .... И даже добавление блока try catch не изменит вывод. Именно сейчас я понимаю, что получаю состояние Canceled только тогда, когда удаляю продолжение и добавляю блок try-catch. (Только удаление блока (конечно) приводит к совокупному исключению). Возможно ли, что RanToCompletion относится к завершению продолжения? Это имело бы смысл, так как я уже был проинформирован об отмене в блоке-продолжении.   -  person FunkyPeanut    schedule 24.12.2014
comment
@dotnetstep Да, это воспроизводимо, и вызов, безусловно, выполняется каждый раз.   -  person FunkyPeanut    schedule 24.12.2014
comment
@kennyzx Что поддерживает мою теорию выше, так это то, что мой код выдает исключение TaskCancellationException, когда я изменяю TaskContinuationOptions на OnNotCancelled. Однако это работает, если установить для него значение NotOnRanToCompletion.   -  person FunkyPeanut    schedule 24.12.2014
comment
Я не могу воспроизвести. Каждый раз, когда он печатает State of the Task is Canceled (отлавливая AggregateException), я пробовал как v4.5, так и v4.5.1 (разницы быть не должно), не могу догадаться, почему это может произойти :(   -  person kennyzx    schedule 24.12.2014
comment
Как я и ожидал, я также не могу воспроизвести неправильное поведение. Я получаю исключение, и статус задачи Canceled. Очевидно, что код, который вы разместили в своем вопросе, либо на самом деле не тот код, который вы используете, либо во всей вашей программе есть какой-то другой код, которым вы не поделились с нами и который вызывает проблему. Опубликуйте хороший пример кода, если вам нужна помощь.   -  person Peter Duniho    schedule 24.12.2014
comment
@ Питер Дунихо Вы правы. Я не совсем понимаю, как я мог это испортить и что испортило, так как моя последняя сохраненная версия исчезла... Мне очень жаль, и все же спасибо за вашу помощь.   -  person FunkyPeanut    schedule 25.12.2014
comment
Necro, а может это была async void ситуация? Хорошее объяснение здесь.   -  person McGuireV10    schedule 03.02.2019