Task构造函数中的取消标记:为什么?
某些System.Threading.Tasks.Task
构造函数将CancellationToken
作为参数:
CancellationTokenSource source = new CancellationTokenSource(); Task t = new Task (/* method */, source.Token);
让我感到困惑的是,从方法体内部无法实际获取传入的令牌(例如,没有像Task.CurrentTask.CancellationToken
)。 令牌必须通过一些其他机制来提供,比如状态对象或者在lambda中捕获。
那么在构造函数中提供取消标记的目的是什么?
将此令牌传递给Task构造函数将其与此任务相关联。
从MSDN引用Stephen Toub的回答 :
这有两个主要的好处:
- 如果令牌在任务开始执行之前有取消请求,则任务将不会执行。 它将立即过渡到已取消,而不是过渡到运行。 这样可以避免运行任务的成本,如果只是在运行时取消这个任务。
- 如果任务主体也在监视取消标记并抛出包含该标记的
OperationCanceledException
(这是ThrowIfCancellationRequested所做的),那么当任务看到OCE时,它会检查OCE的标记是否与任务的标记相匹配。 如果确实如此,那么这个例外就被视为确认合作取消,并且任务转换到取消状态(而不是故障状态)。
构造函数在内部使用令牌进行取消处理。 如果你的代码想访问令牌,你有责任把它传递给你自己。 我强烈build议您在CodePlex上阅读使用Microsoft .NET编写的Parallel Programming 。
书中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.CompleteAdding(),因此一个线程在blockingCollection.Take()上被阻塞,那么应该唤醒第一个调用并抛出InvalidOperationException来表示不正确的用法。
http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx