2016-11-28 3 views
0

Я смущаюсь за отмену нескольких задач и продолжаю задачу по отображению результата. Согласно тому, что я понял, эта программа должна отображатьОтмена задач и продолжение с

Задачи отменили

CancellationTokenSource cts = new CancellationTokenSource(); 
List<Task> tasks = new List<Task>(); 
for(int i= 0; i<3; i++) 
{ 
    tasks.Add(Task.Run(() =>{ 
     while(!cts.Token.IsCancellationRequested) 
      Thread.Sleep(500); 

     // Uncomment this to see 'Tasks canceled' in the result 
     //if(cts.Token.IsCancellationRequested) 
     // cts.Token.ThrowIfCancellationRequested(); 
    },cts.Token)); 
} 

Task.WhenAll(tasks).ContinueWith(task => 
{ 
    if(task.IsCanceled) 
     Console.WriteLine("Tasks canceled"); 
    if(task.IsCompleted) 
     Console.WriteLine("Tasks completed"); 
}); 
Thread.Sleep(2000); 
cts.Cancel(); 

К сожалению, отображение

Задачи, решаемые

Если я раскомментировать бросание отменить исключение дисплей программа

Задачи отменили

Задачи, решаемые

Почему? кажется, что я что-то пропустил, но я не вижу, что ...

+0

Завершено верно, потому что оно закончилось .. не потому что оно дошло до конца без проблем – BugFinder

+3

Чтобы «отменить» токен отмены, автоматически не отменяет никаких задач. Если вы не выполняете «ThrowIfCancellationRequested», задача просто не отменяется, поэтому вы не видите ожидаемого результата. –

+0

См. Второй комментарий к второму принятому отвечу здесь: http://stackoverflow.com/questions/7343211/cancelling-a-task-is-throwing-an-exception – PaulF

ответ

1

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

По дизайну, чтобы действительно отменить задачу, вам нужно сделать исключение для изменения потока выполнения. Фактически, в вашем примере кода не требуется инструкция if - метод ThrowIfCancellationRequested будет обрабатывать эту проверку сам по себе и будет передавать исключение, если была запрошена отмена.

Что касается последней части, вот выдержка из MSDN:

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

https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.iscompleted(v=vs.110).aspx

Таким образом, задача будет завершена, даже если она была отменена.

+0

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

+1

@Troopers Потому что именно так они были разработаны для работы. – Servy

0

на основе док

Task.WhenAll 

Создает задачу, которая будет завершена, когда все задачи и объекты в массиве завершена.

поэтому задача является гарантией быть в полном состоянии после всех ваших 3-х задач закончилась

То, что вы хотите, вероятно,

Task.WhenAll(tasks).Wait(); 
Foreach(Task task in tasks) 
{ 
    if(task.IsCanceled) 
     Console.WriteLine("Tasks canceled"); 
    if(task.IsCompleted) 
     Console.WriteLine("Tasks completed"); 
} 

Edit: Причина, почему задача не отменяется потому что вы никогда не бросаете это исключение. Давайте представим этот случай: Ваша задача почти завершена, когда вы вызываете cts.Cancel();. После того, как вы вызываете это, задача завершена. Таким образом, ничто в вашей задаче не отменено и, следовательно, оно не отмечено как отмененное.

+0

Вопрос в том, почему задачи не отмечены как отмененные. Когда вы ждете выполнения задачи, ее все равно можно отменить. – Servy

+0

Извините, вы в отпуске – Troopers

+0

@Servy понял это неправильно и отредактировал – Steve