Токен отмены в конструкторе задач: почему?
некоторых System.Threading.Tasks.Task конструкторы возьми CancellationToken параметр:
CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);
что меня удивляет в этом то, что нет никакого способа от внутри тело метода, чтобы фактически получить маркер, переданный в (например, ничего подобного Task.CurrentTask.CancellationToken). Маркер должен быть предоставлен через какой-то другой механизм, такой как объект состояния или захваченный в лямбде.
Итак, какой цели служит предоставление токена отмены в конструкторе?
3 ответов:
передача этого маркера в конструктор задачи связывает его с этой задачей.
цитирую ответ Стивена туба от MSDN:
этот имеет два основных преимущества:
- если токен имеет отмену, запрошенную до начала выполнения задачи, Задача не будет выполняться. Вместо того, чтобы переходить к Запустив, он сразу же перейдет на отмененный. Это позволяет избежать затраты на выполнение задачи, если бы это было просто отменяется во время работы в любом случае.
- если тело задачи также отслеживает токен отмены и выдает
OperationCanceledExceptionсодержащие этот знак (что и делает ThrowIfCancellationRequested), то когда задача видит, что OCE, он проверяет, соответствует ли токен OCE задаче знак. Если это так, то это исключение рассматривается как подтверждение совместная отмена и переход задачи к отмененной государство (а не виноватый государство.)
конструктор использует маркер для внутренней обработки отмены. Если ваш код хочет получить доступ к токену, вы несете ответственность за его передачу себе. Я бы очень рекомендовал прочитать параллельное программирование с 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();
отмена не простой случай, как многие могли бы подумать. Некоторые из тонкостей объясняются в этом блоге на msdn:
например:
в некоторых ситуациях в параллельных расширениях и в других системах это необходимо разбудить заблокированный метод по причинам, которые не связаны до явной отмены пользователем. Например, если один поток заблокирован на blockingCollection.Take () из-за того, что коллекция пуста и еще одна нить впоследствии звонки blockingCollection.CompleteAdding (), то первый вызов должен проснуться вверх и бросьте исключение InvalidOperationException для представления неправильного использование.
http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx
Comments