2017-01-27 11 views
1

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

void Main() 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(0,0,0,0,1000)); 

    Task t = Task.Run(() => Work(),cts.Token); 
    try 
    { 
     t.Wait(); 
    } 
    catch 
    { 
    } 

    ("Completed :: " + t.IsCompleted).Dump(); 
    ("Canceled :: " + t.IsCanceled).Dump(); 
    ("Faulted :: " + t.IsFaulted).Dump(); 
} 

public async Task Work() 
{ 
    await Task.Delay(3000); 
} 

Ниже приведены вопросы:

  1. Я могу с уверенностью выяснить Заполненный и FAULTED состояния, но даже тогда, когда на мой взгляд, этот код должен привести к отмене задач, значение IsCanceled свойство всегда ложно.

  2. В идеале, когда задача нарушенные, хотя я молча захватывая исключение в попытке поймать блок, он должен показать IsCompleted как ложный, но всегда остается в силе, в настоящее время LINQPad не продолжать вариант ошибки, но я предполагаю, что было бы превратить ложь, если я могу продолжить на ошибки

+0

Отмена * кооператив *. Ваша задача проигнорировала ваш токен отмены и вместо этого остановилась. Поэтому он не был отменен. –

+0

Какую модификацию я должен сделать, чтобы заставить это работать, и является ли мое другое понимание правильным, если оно распространяется, тогда оно должно быть ошибочно не завершено? –

ответ

4

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

В отмене автоматизма нет. Вы проходите мимо CancellationToken до Task.Run. Если при запуске задачи произойдет отмена, процесс запуска будет прерван отменой. Когда задача запущена, задача метода заключается в проверке токена отмены. Wait не делает это. Он даже не знает токен отмены. Следовательно, задача не может превратиться в отмененное состояние.

Это, как вы бы наблюдать аннулирование:

void Main() 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(0,0,0,0,1000)); 

    Task t = Task.Run(() => Work(cts.Token),cts.Token); 
    try 
    { 
     t.Wait(); 
    } 
    catch 
    { 
    } 

    ("Completed :: " + t.IsCompleted).Dump(); 
    ("Canceled :: " + t.IsCanceled).Dump(); 
    ("Faulted :: " + t.IsFaulted).Dump(); 
} 

public async Task Work(CancellationToken token) 
{ 
    await Task.Delay(3000, token); 
} 

В идеале, когда задача нарушенное, хотя я молча захватывая исключение в попытке поймать блок, он должен показать IsCompleted как ложный, но всегда остаются верными

Проверить MSDN:

IsCompleted вернет true, когда задача находится в одном из трех конечных состояний: RanToCompletion, Faulted или Canceled.

+0

Спасибо за подробный набор деталей и ответив на все вопросы –

2

Вы не прошли CancellationToken методу Task.Delay, так что ничто не должно было быть отменено. Токен, который вы передаете в Task.Run(xxx), предотвращает запуск работы, если токен имеет отменную отмену. Но ваш токен отменяется через 1 секунду, то есть после звонка Task.Run.

Попробуйте это:

void Main() 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(0, 0, 0, 0, 1000)); 

    Task t = Task.Run(() => Work(cts.Token), cts.Token); 
    try 
    { 
     t.Wait(); 
    } 
    catch 
    { 
    } 

    ("Completed :: " + t.IsCompleted).Dump(); 
    ("Canceled :: " + t.IsCanceled).Dump(); 
    ("Faulted :: " + t.IsFaulted).Dump(); 
} 

public async Task Work(CancellationToken t) 
{ 
    await Task.Delay(3000, t); 
} 
+0

Спасибо за ответ, оцените, он помогает –

4

Другие отметили, что ваш код не соблюдает CancellationToken, и поэтому задача не отменяется.

Отвечу эту часть вопроса:

Я хочу, чтобы выполнить логику только тогда, когда задача выполнена, но не нарушенную или отменена.

Чтобы сделать это, поместите вашу логику после того как вы await задачу:

await t; 
// Your logic here. 

Использование IsCanceled/IsFaulted/IsCompleted для управления потоком является кодом запаха.

+0

Спасибо @StephenCleary за важные детали, на самом деле это как мой код, у меня есть количество разных 'Task ' завернутых внутри 'List ' и я вызвал 'await Task.WhenAll (TaskList)', я не понял, что это вызовет любое исключение в базовых задачах для вызывающего, я подумал, что это будет молча включать исключение, и мне нужно явно определить, какие задачи содержат действительный результат, а какой - ошибочно/отменен, но, как вы уточнили, это неверно, когда ожидание используется для разворота –