C# 为什么会出现TaskCanceledException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15181855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does TaskCanceledException occur?
提问by net_prog
I have the following test code:
我有以下测试代码:
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);
}
In the thread methods I don't throw any exceptions, but I get TaskCanceledException
in try-catch
block of the outer code which starts the tasks. Why this happens and what is the purpose of token.ThrowIfCancellationRequested();
in this case. I believe the exception should only be thrown if I call token.ThrowIfCancellationRequested();
in the thread method.
在线程方法中,我不抛出任何异常,但我进入TaskCanceledException
了try-catch
启动任务的外部代码块。为什么会发生这种情况以及token.ThrowIfCancellationRequested();
在这种情况下的目的是什么。我相信只有在调用token.ThrowIfCancellationRequested();
线程方法时才会抛出异常。
采纳答案by Joshua
I believe this is expected behavior because you're running in to a variation of a race condition.
我相信这是预期的行为,因为您遇到了竞争条件的变化。
From How to: Cancel a task and its children:
The calling thread does not forcibly end the task; it only signals that cancellation is requested. If the task is already running, it is up to the user delegate to notice the request and respond appropriately. If cancellation is requested before the task runs, then the user delegate is never executed and the task object transitions into the
Canceled
state.
调用线程不会强行结束任务;它仅表示请求取消。如果任务已经在运行,则由用户委托来通知请求并做出适当的响应。如果在任务运行之前请求取消,则永远不会执行用户委托并且任务对象转换为
Canceled
状态。
and from Task Cancellation:
来自任务取消:
You can terminate the operation by [...] simply returning from the delegate. In many scenarios this is sufficient; however, a task instance that is "canceled" in this way transitions to the
RanToCompletion
state, not to theCanceled
state.
您可以通过 [...] 简单地从委托返回来终止操作。在许多情况下,这已经足够了;但是,以这种方式“取消”的任务实例会转换到
RanToCompletion
状态,而不是Canceled
状态。
My educated guess here is that while you are calling .Start()
on your two tasks, chances are that one (or both of them) didn't actually start before you called .Cancel()
on your CancellationTokenSource
. I bet if you put in at least a three second wait between the start of the tasks and the cancellation, it won't throw the exception. Also, you can check the .Status
property of both tasks. If I'm right, the .Status
property should read TaskStatus.Canceled
on at least one of them when the exception is thrown.
我有根据的猜测是,当你调用.Start()
你的两个任务时,很可能一个(或两个)在你调用.Cancel()
你的CancellationTokenSource
. 我敢打赌,如果您在任务开始和取消之间至少等待三秒钟,它就不会抛出异常。此外,您可以检查这.Status
两个任务的属性。如果我是对的,当抛出异常时,该.Status
属性应该TaskStatus.Canceled
至少读取其中之一。
Remember, starting a new Task
does not guarantee a new thread being created. It falls to the TPL to decide what gets a new thread and what is simply queued for execution.
请记住,启动一个Task
新线程并不能保证创建一个新线程。由 TPL 决定什么获得新线程以及什么只是排队等待执行。