当 Task.IsCancelled 被设置为 true 时会发生什么?

3

什么时候会出现Task.IsCanceled = true;

代码:

var cts = new CancellationTokenSource();
string result = "";
cts.CancelAfter(10000);
try
{
    Task t = Task.Run(() =>
    {
        using (var stream = new WebClient().OpenRead("http://www.rediffmail.com"))
        {
            result = "success!";
        }
        cts.Token.ThrowIfCancellationRequested();
    }, cts.Token);
    
    Stopwatch timer = new Stopwatch();
    timer.Start();
    while (timer.IsRunning)
    {
        if (timer.ElapsedMilliseconds <= 10000)
        {
            if (result != ""){                                                                                      
                timer.Stop();
                Console.WriteLine(result);
            }
        }
        else
        {
            timer.Stop();
            //cts.Cancel();
            //cts.Token.ThrowIfCancellationRequested();
        }
    }
}
catch (OperationCanceledException)
{
    Console.WriteLine(t.IsCanceled); // still its appear in false.
}

我的要求是 - 如果任务未在10秒内完成,需要取消任务。
因此我设置了计时器并监视给定的秒数。如果任务未完成,则取消任务并显示错误消息。

3
请提供一个最小、完整且可验证的示例。您所展示的内容不完整。 - Igor
1
取消令牌不足够,您需要检查“method”代码以取消作业。 - VMAtm
1
你能展示一下等待 Task t 的代码吗?并且,如果该方法运行时间超过 20 秒,你想要取消整个操作,是吗? - Peter Bons
我应该在哪里分享代码?这里无法分享代码,显示“太长”。 - Gokul Kumar
2个回答

4
从文档中可以得知:
任务将在以下任何情况下以TaskStatus.Canceled状态完成: 1. 在任务开始执行之前,其CancellationToken被标记为取消。 2. 任务通过抛出一个带有相同CancellationToken的OperationCanceledException来响应其已经发出信号的CancellationToken上的取消请求。 3. 任务通过在CancellationToken上调用ThrowIfCancellationRequested方法来响应其已经发出信号的CancellationToken上的取消请求。
因此,基本上您需要在任务中抛出OperationCanceledException,以通过执行cts.Token.ThrowIfCancellationRequested()来强制该状态,例如在取消后立即执行。
但是,这种机制的意图有点相反。您取消源时,比如用户在窗体上按下取消按钮(从任务外部),任务仅在其代码的某些安全可取消点验证是否请求了取消。

3
你需要将令牌传递给你的方法。它应该检查令牌并尊重 CancellationTokenSourceCancel() 调用。
或者你可以自己来做:
Task t = Task.Factory.StartNew(() =>
{
    myResult = method();  // Request processing in parallel

    cts.Token.ThrowIfCancellationRequested(); // React on cancellation 
}, cts.Token);

一个完整的示例是这样的:
async Task Main()
{
    var cts = new CancellationTokenSource();
    var ct = cts.Token;
    cts.CancelAfter(500);

    Task t = null;
    try
    {
        t = Task.Run(() => { Thread.Sleep(1000); ct.ThrowIfCancellationRequested(); }, ct);
        await t;
        Console.WriteLine(t.IsCanceled);
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine(t.IsCanceled);
    }
}

输出结果是抛出一个“OperationCanceledException”异常,结果为True。如果删除“ct.ThrowIfCancellationRequested();”部分,则会显示False。
编辑:现在,您已经更新了问题,对此进行一些评论。首先,由于您正在使用“CancelAfter”方法,因此不再需要定时器。其次,您需要等待任务完成。因此,代码应该像这样:
string result = "";
cts.CancelAfter(10000);
Task t = null;
try
{
    t = Task.Run(() =>
    {
        using (var stream = new WebClient().OpenRead("http://www.rediffmail.com"))
        {
            cts.Token.ThrowIfCancellationRequested();
            result = "success!";
        }
    }, cts.Token);

    await t;
}
catch (OperationCanceledException)
{
    Console.WriteLine(t.IsCanceled); 
}

这应该表明当WebClient的呼叫时间超过10秒时,t.IsCanceledtrue


Task t = Task.Factory.StartNew(() => { myResult = method(); // 并行请求处理 }, cts.Token); // 一段时间后 cts.cancel cts.Token.ThrowIfCancellationRequested(); 这是否可能?在这里,t.iscancelled 永远不会为 true。 - Gokul Kumar
你能展示一下等待Task t的代码吗?并且为了正确,如果这个方法运行时间超过20秒,你想要取消整个操作,是吗? - Peter Bons
如何分享代码?这里的字符太长了。 - Gokul Kumar
请提供需要翻译的具体内容。 - Peter Bons
你能把你的压缩代码放在Dropbox/OneDrive或其他地方,这样我就可以看一下吗? - Peter Bons
显示剩余4条评论

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