任务构建器中的取消令牌:为什么?
-
02-10-2019 - |
题
肯定 System.Threading.Tasks.Task
构造师占用 CancellationToken
作为参数:
CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);
令我感到困惑的是,没有办法 里面 实际获取令牌的方法主体(例如,没有什么比 Task.CurrentTask.CancellationToken
)。必须通过其他一些机制来提供令牌,例如状态对象或在lambda中捕获。
那么,在构造函数中提供取消令牌的目的是什么?
解决方案
将此令牌传递到任务构造函数中,将其与此任务相关联。
这有两个主要好处:
- 如果令牌在任务开始执行之前已请求取消,则任务将无法执行。而不是过渡到
Running
, ,它会立即过渡到Canceled
. 。如果无论如何在运行时都会被取消,则可以避免运行任务的成本。- 如果任务的主体还在监视取消令牌并抛出
OperationCanceledException
包含该令牌(这是什么ThrowIfCancellationRequested
),然后任务看到OperationCanceledException
, ,它检查了是否OperationCanceledException
的令牌与任务的令牌匹配。如果确实如此,则该例外被视为合作取消的确认,并且任务过渡到已取消状态(而不是故障状态)。
其他提示
构造函数使用令牌进行内部取消处理。如果您的代码希望访问令牌,则负责将其传递给自己。我强烈建议您阅读 与Microsoft .NET书籍的平行编程在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的博客文章中解释了一些微妙之处:
例如:
在某些情况下,在并行扩展和其他系统中,有必要唤醒被阻止的方法,原因是用户明确取消的原因。例如,如果一个线程在blockingCollection.take()上被阻止,因为该集合为空并且另一个线程随后呼叫blockingCollection.completeadding(),则第一个调用应唤醒并投掷InvalidoperationException以表示不正确的用法。
http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx
不隶属于 StackOverflow