为什么发生TaskCanceledException?

我有以下testing代码:

void Button_Click(object sender, RoutedEventArgs e) { var source = new CancellationTokenSource(); var tsk1 = new Task(() => Thread1(source.Token), source.Token); var tsk2 = new Task(() => Thread2(source.Token), source.Token); tsk1.Start(); tsk2.Start(); source.Cancel(); try { Task.WaitAll(new[] {tsk1, tsk2}); } catch (Exception ex) { // here exception is caught } } void Thread1(CancellationToken token) { Thread.Sleep(2000); // If the following line is enabled, the result is the same. // token.ThrowIfCancellationRequested(); } void Thread2(CancellationToken token) { Thread.Sleep(3000); } 

在线程方法中,我不会抛出任何exception,但是我会在启动任务的外部代码的try-catch块中得到TaskCanceledException 。 为什么会发生这种情况, token.ThrowIfCancellationRequested();的目的是什么token.ThrowIfCancellationRequested(); 在这种情况下。 我相信只有在调用token.ThrowIfCancellationRequested();才会抛出exceptiontoken.ThrowIfCancellationRequested(); 在线程方法中。

我相信这是预期的行为,因为你正在跑步的竞争条件的变化。

从如何操作:取消任务及其子项 :

调用线程不会强行结束任务; 它只是表示要求取消。 如果任务已经运行,则由用户委托来注意请求并做出适当的响应。 如果在任务运行之前请求取消,那么用户委托永远不会执行,任务对象将转换为Canceled状态。

并从任务取消 :

您可以通过简单地从代表处返回来终止操作。 在很多情况下,这就足够了。 但是,以这种方式“取消”的任务实例将转换为RanToCompletion状态,而不是“ Canceled状态。

我的教育猜测是,当你在你的两个任务中调用.Cancel() ,在CancellationTokenSource上调用.Cancel()之前,其中一个(或两个)实际上并没有启动。 我敢打赌,如果你在任务开始和取消之间至less要等三秒钟,那么就不会抛出exception。 另外,您可以检查两个任务的.Status属性。 如果我是正确的,当抛出exception时, .Status属性应该至less读取其中的一个TaskStatus.Canceled

记住,开始一个新的Task并不能保证正在创build一个新的线程。 它由TPL决定什么得到一个新的线程,什么是排队等待执行。