【问题标题】:when Task.IsCancelled is set as true?当 Task.IsCancelled 设置为 true 时?
【发布时间】:2017-06-28 17:50:07
【问题描述】:

什么时候来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 秒内未完成,需要取消任务。

所以我正在设置计时器并观看给定的秒数。它未完成意味着取消任务并显示错误消息。

【问题讨论】:

  • 请附上Minimal, Complete, and Verifiable example。您显示的内容不完整。
  • 取消token还不够,需要查看method取消作业的代码
  • 你能显示等待任务 t 的代码吗?正确地说,如果方法运行时间超过 20 秒,您想取消整个操作,是吗?
  • 我将在哪里共享代码。这里无法分享代码。显示时间过长

标签: c# task-parallel-library task cancellationtokensource cancellation-token


【解决方案1】:

您必须将令牌传递给您的方法。它应该检查令牌并尊重对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被抛出,结果是

是的

如果您删除 ct.ThrowIfCancellationRequested(); 部分,它将显示

错误

编辑:

现在,您已经更新了问题,一些 cmets 对此进行了更新。首先,您将不再需要计时器,因为您使用的是CancelAfter 方法。其次,你需要await你的任务。所以这就是这样的:

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); 
}

这应该表明t.IsCanceledtrue 但当然只有当WebClient 的调用需要超过10 秒时。

【讨论】:

  • Task t = Task.Factory.StartNew(() => { myResult = method(); // 请求并行处理 }, cts.Token); // 一段时间后 cts.cancel cts.Token.ThrowIfCancellationRequested();有可能吗?这里 t.iscancelled 永远不会出现 true。
  • 你能显示等待任务 t 的代码吗?正确地说,如果方法运行时间超过 20 秒,您想取消整个操作,是吗?
  • 如何分享代码?这里出现了太长的字符。
  • 编辑或添加到您的问题中,这是最好的方法。
  • 它不工作。 Web 客户端需要 10 秒。但它仍然没有来进行捕获操作。获得结果后,由于等待操作,只会返回结果。没有等待它可能吗?
【解决方案2】:

来自文档:

在以下任一条件下,任务将在 TaskStatus.Canceled 状态下完成:

  1. 它的 CancellationToken 在任务开始执行之前被标记为取消。

  2. 任务通过抛出带有相同 CancellationToken 的 OperationCanceledException 来确认其已发出信号的 CancellationToken 的取消请求。

  3. 任务通过调用 CancellationToken 上的 ThrowIfCancellationRequested 方法,在其已发出信号的 CancellationToken 上确认取消请求。

所以基本上你需要在你的任务中抛出一个OperationCanceledException来强制状态,例如在你取消它之后执行cts.Token.ThrowIfCancellationRequested()

但是这种机制的意图有点相反。您取消源说,当用户按下表单上的取消按钮(从您的任务之外)时,任务只是验证是否在某些安全的情况下请求取消以取消其代码的点。

【讨论】:

    猜你喜欢
    • 2016-06-13
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    相关资源
    最近更新 更多