我们得到以下情况:
class Program
{
static void Main(string[] args)
{
// trigger the delayed function
trigger();
// cancel the running task.
_token.Cancel();
// keep window open ;-)
Console.ReadLine();
}
private static CancellationTokenSource _token = null;
private static async void trigger()
{
_token = new CancellationTokenSource();
try
{
// run task
await Task.Run(async () =>
{
// wait time
await Task.Delay(2500);
// we should be cancelled here !!
Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
Console.WriteLine("SHOULD NOT HAPPEN");
}, _token.Token);
}
catch (TaskCanceledException)
{
}
}
}
IMO预期的行为是,在处理 Task.Delay(2500)之后,任务的操作主要被取消。
但控制台正在打印:
IsCancellationRequested=True
SHOULD NOT HAPPEN
这只是一个错误。如果将 CancellationToken 作为参数添加到 Task.Delay -Function,它将按预期工作。
那么如果任务中的函数使用 Task.Delay ,你可能不知道如何处理取消?
答案 0 :(得分:3)
.Net中的取消是合作的。将令牌作为参数传递给Task.Run
只会将令牌与返回的任务相关联。
要实际取消任务,您需要检查任务本身内的令牌。如果您希望在延迟内部取消任务,则需要将令牌传递给Task.Delay
方法。否则,您只能在延迟之前或之后检查:
await Task.Run(async () =>
{
_token.Token.ThrowIfCancelltionRequested();
await Task.Delay(2500, _token.Token);
_token.Token.ThrowIfCancelltionRequested();
Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
Console.WriteLine("SHOULD NOT HAPPEN");
}, _token.Token);
答案 1 :(得分:1)
这是一篇很好的MSDN文章:https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx
调用线程不强制结束任务;它只发出信号 请求取消。如果任务已经在运行,那就是 由用户委托来通知请求并做出响应 适当。如果在任务运行之前请求取消,那么 永远不会执行用户委托,并且任务对象会转换 进入已取消状态。
正如i3arnon建议你可以在执行实际工作之前检查状态并抛出异常。代码摘自文章:
...
// Was cancellation already requested?
if (ct.IsCancellationRequested == true) {
Console.WriteLine("Task {0} was cancelled before it got started.",
taskNum);
ct.ThrowIfCancellationRequested();
}
...