为什么TaskCanceledException发生?(Why does TaskCanceledE

2019-08-17 06:44发布

我有以下的测试代码:

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);
}

在线程的方法,我不抛出任何异常,但我得到TaskCanceledExceptiontry-catch这将启动任务外码的块。 为什么出现这种情况,什么是目的token.ThrowIfCancellationRequested(); 在这种情况下。 我相信,如果我叫异常应仅被抛出token.ThrowIfCancellationRequested(); 在螺纹方法。

Answer 1:

我相信这是因为你在对竞争条件的变化运行的预期行为。

从如何:取消任务及其子 :

调用线程不强行结束任务; 它只是预示着取消请求。 如果任务已经在运行,它是由用户委托的通知请求并作出适当的反应。 如果任务运行之前请求取消,则永远不会执行用户委托和任务对象过渡到Canceled状态。

从任务取消 :

您可以通过终止[...]简单地从委托返回操作。 在许多情况下,这是足够的; 然而,以这种方式转换为“取消”任务实例RanToCompletion状态,而不是到Canceled状态。

我在这里受教育的猜测是,当你调用.Start()在你的两个任务,有机会,一个(或两者)并没有真正开始你叫前.Cancel()在你的CancellationTokenSource 。 我敢打赌,如果你把至少三级秒钟的等待任务的开始和取消之间,也不会抛出异常。 此外,您还可以检查.Status的两个任务性能。 如果我是对的, .Status属性应阅读TaskStatus.Canceled当异常被抛出它们中的至少一个。

记住,开始一个新的Task并不能保证正在创建一个新的线程。 它属于第三方物流来决定哪些得到一个新的线程,什么是简单地排队等待执行。



文章来源: Why does TaskCanceledException occur?