如何使用CancellationToken取消任务?

14

所以我有这段代码:

//CancelationToken
CancellationTokenSource src = new CancellationTokenSource();
CancellationToken ct = src.Token;
ct.Register(() => Console.WriteLine("Abbruch des Tasks"));
//Task
Task t = new Task(() =>
{
    System.Threading.Thread.Sleep(1000);
    if (ct.IsCancellationRequested)
    {
        try
        {
            //Throw
            ct.ThrowIfCancellationRequested();                        
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine(
                "ThrowIfCancellationRequested() liefert eben eine Exception");
        }
    }             

}, ct);
//Run Task and Cancel
t.Start();
src.CancelAfter(350);
t.Wait();

// Get Information
Console.WriteLine("Canceled: {0} . Finished: {1} . Error: {2}",
                    t.IsCanceled, t.IsCompleted, t.IsFaulted);

在这种情况下,我取消了我的任务,但最终的输出是:"Canceled: False . Finished: True . Error: False"。

在我看来,它应该是"Canceled:True . Finished:False"。为什么会得到这个结果?因为我试图捕获异常吗?

我尝试过不使用try-catch块,但由于OperationCanceledException,我的程序停止了。有人可以帮我吗?


在这里看一下:https://msdn.microsoft.com/zh-cn/library/dd997396(v=vs.110).aspx。移除 try..catch 并将其放置在 t.Wait(); 周围即可。 - Frank J
1个回答

16

您目前将异常吞掉了,因此任务被标记为已完成,实际上您处理了异常并且它没有向外传播。

相反,不要在委托内部捕获异常,而是在外部捕获:

void Main()
{
    CancellationTokenSource src = new CancellationTokenSource();
    CancellationToken ct = src.Token;
    ct.Register(() => Console.WriteLine("Abbruch des Tasks"));

    Task t = Task.Run(() =>
    {
        System.Threading.Thread.Sleep(1000);
        ct.ThrowIfCancellationRequested();
    }, ct);

    src.Cancel();
    try
    {
        t.Wait();
    }
    catch (AggregateException e)
    {
        // Don't actually use an empty catch clause, this is
        // for the sake of demonstration.
    }

    Console.WriteLine("Canceled: {0} . Finished: {1} . Error: {2}",
                       t.IsCanceled, t.IsCompleted, t.IsFaulted);
}

谢谢你的回答。有一个问题,为什么令牌(ct)需要在操作(第10行)和任务(第11行)中都添加? - Frank Yuan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接