Токен отмены в конструкторе задачи: почему?
-
02-10-2019 - |
Вопрос
Определенный System.Threading.Tasks.Task
Конструкторы принимают CancellationToken
как параметр:
CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);
Что меня сбивает с толку, так это то, что нет никакого способа от внутри тело метода, которое фактически попало в токен, пройденное (например, ничего похожего на Task.CurrentTask.CancellationToken
) Токен должен быть предоставлен с помощью какого -либо другого механизма, такого как объект состояния или запечатлен в лямбде.
Так какую цель предоставит токен отмены в конструкторе?
Решение
Передача этого токена в конструктор задачи связывает его с этой задачей.
Цитата Ответ Стивена Тоуба от MSDN:
Это имеет два основных преимущества:
- Если токен имеет отмену, запрошенную до начала выполнения задачи, задача не выполняется. А не переходить на
Running
, это сразу же перейдет кCanceled
. Анкет Это избегает затрат на выполнение задачи, если она будет просто отменена во время работы.- Если тело задания также контролирует токен отмены и бросает
OperationCanceledException
содержащий этот токен (что и чтоThrowIfCancellationRequested
делает), тогда, когда задача видит, чтоOperationCanceledException
, это проверяет, есть лиOperationCanceledException
Токен соответствует жетону задачи. Если это произойдет, это исключение рассматривается как подтверждение отмены кооперативной отмены, а задача переходит в отмененное состояние (а не в неисправное состояние).
Другие советы
Конструктор использует токен для обработки отмены внутренне. Если ваш код хотел бы получить доступ к токену, вы несете ответственность за передачу его себе. Я очень рекомендую прочитать Параллельное программирование с книгой Microsoft .net At Codeplex.
Пример использования CT из книги:
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task myTask = Task.Factory.StartNew(() =>
{
for (...)
{
token.ThrowIfCancellationRequested();
// Body of for loop.
}
}, token);
// ... elsewhere ...
cts.Cancel();
Отмена не является простым случаем, как многие могут подумать. Некоторые из тонкостей объяснены в этом блоге на MSDN:
Например:
В определенных ситуациях в параллельных расширениях и в других системах необходимо разбудить заблокированный метод по причинам, которые не связаны с явной отменой пользователем. Например, если один поток блокируется на блокировке.
http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx