Токен отмены в конструкторе задач: почему? - PullRequest
212 голосов
/ 15 сентября 2010

Некоторые конструкторы System.Threading.Tasks.Task принимают CancellationToken в качестве параметра:

CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);

Что меня сбивает с толку, так это то, что от внутри тела метода невозможно перейти кполучить токен, переданный в (например, ничего подобного Task.CurrentTask.CancellationToken).Токен должен быть предоставлен через какой-то другой механизм, такой как объект состояния, или захвачен в лямбду.

Так для чего служит предоставление токена отмены в конструкторе?

Ответы [ 3 ]

246 голосов
/ 15 сентября 2010

Передача этого токена в конструктор задач связывает его с этой задачей.

Цитата Ответ Стивена Тауба из MSDN :

Это имеет два основных преимущества:

  1. Если токен запросил отмену до начала выполнения Задачи, Задача не будет выполнена. Вместо перехода к Running, он немедленно перейдет к Canceled. Это позволяет избежать затраты на выполнение задачи, если она будет отменена во время выполнения в любом случае.
  2. Если тело задачи также отслеживает токен отмены и выдает OperationCanceledException, содержащий этот токен (что делает ThrowIfCancellationRequested), то когда задача видит, что OperationCanceledException, он проверяет, совпадает ли токен OperationCanceledException с задачей маркер. Если это так, то это исключение рассматривается как подтверждение Совместное аннулирование и переходы Задания в Отменено состояние (а не состояние Failed).
28 голосов
/ 15 сентября 2010

Конструктор использует токен для внутренней обработки отмены.Если ваш код хочет получить доступ к токену, вы несете ответственность за передачу его себе.Я настоятельно рекомендую прочитать книгу Параллельное программирование с Microsoft .NET на CodePlex .

Пример использования CTS из книги:

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    for (...)
    {
        token.ThrowIfCancellationRequested();

        // Body of for loop.
    }
}, token);

// ... elsewhere ...
cts.Cancel();
7 голосов
/ 15 сентября 2010

Отмена - не простой случай, как многие могут подумать.Некоторые тонкости объясняются в этом сообщении в блоге на msdn:

Например:

В определенных ситуациях в параллельных расширениях и в других системах необходимо пробуждать заблокированныеметод по причинам, которые не связаны с явной отменой пользователем.Например, если один поток заблокирован в blockingCollection.Take () из-за того, что коллекция пуста, а другой поток впоследствии вызывает blockingCollection.CompleteAdding (), то первый вызов должен активироваться и выдать исключение InvalidOperationException для представления неправильного использования.

http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx

...