我需要调用我的Task对象的一个方法。我的任务执行某种读取,如果完成时间超过2秒,我将取消操作。
我将此代码作为模拟:
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(2000));
var task = Task.Run(() =>
{
try
{
int i = 0;
while (true)
{
Thread.Sleep(500);
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("i = {0}", i);
i++;
if (i > 3) throw new InvalidOperationException();
}
}
catch (Exception e)
{
Console.WriteLine("Exception {0}", e.Message);
throw;
}
});
task.ContinueWith(t => Console.WriteLine(t.Status), TaskContinuationOptions.NotOnRanToCompletion);
我的控制台输出如下:
这是我期望并为我工作的。如果我复制任务中的代码并创建一个方法,我不再将任务状态设置为已取消。我的状态为Faulted。我必须知道操作是否被取消或者在阅读过程中是否发生了异常。我无法弄清楚为什么我没有在这里取消任务状态。
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(2000));
var task = Task.Run(() =>
{
try
{
Tester(cts);
}
catch (Exception e)
{
Console.WriteLine("Exception {0}", e.Message);
throw;
}
});
private static void Tester(CancellationTokenSource cts)
{
int i = 0;
while (true)
{
Thread.Sleep(500);
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("i = {0}", i);
i++;
if (i > 3) throw new InvalidOperationException();
}
}
答案 0 :(得分:2)
如果您将令牌传递给Canceled
,则会获得预期的Task.Run
结果:
var task = Task.Run(() =>
{
try
{
Tester(cts);
}
catch (Exception e)
{
Console.WriteLine("Exception {0}", e.Message);
throw;
}
}, cts.Token);
任务需要知道哪个令牌会抛出OperationCanceledException
- 只有来自正确源的异常才会取消任务,其他每个异常都会将其置为错误。
来自MSDN:
当任务实例观察到用户代码抛出的OperationCanceledException时,它会将异常的标记与其关联的标记(传递给创建Task的API的标记)进行比较。如果它们相同且令牌的IsCancellationRequested属性返回true,则任务将其解释为确认取消并转换为已取消状态。
我不完全理解为什么你首先得到Canceled
结果,看起来它与捕获CancellationTokenSource
时有关。