【问题标题】:task IsCanceled is false, while I canceled任务 IsCanceled 为假,而我取消了
【发布时间】:2013-09-15 06:57:29
【问题描述】:

当我取消任务时,IsCanceled 属性的等待结果仍然返回 true。好像出了点问题。

请指教。 这是代码:

CancellationTokenSource _cancelLationToken = new CancellationTokenSource();

private async void Button_Click(object sender, EventArgs e)
{
    _cancelLationToken = new CancellationTokenSource();
    _cancelLationToken.Token.Register(theCallBack);
    var myTaskToWaitFor = Task.Factory.StartNew(() => WorkHard(_cancelLationToken.Token), _cancelLationToken.Token);
    await myTaskToWaitFor;

    int i=0;

    if(myTaskToWaitFor.IsCanceled)
        i = i; //breakpoint for debugging
    else
        i = i; //breakpoint for debugging <== always ends here... :-(
}

private void WorkHard(CancellationToken token)
{
    for(int i = 0; i < 100000000; i++)
        if(token.IsCancellationRequested)
            break;
        else
            Math.Acos(Math.Pow(i, i / 10000000));
}

public void theCallBack()
{
    //todo: do something
}

private void CancelButton_Click(object sender, EventArgs e)
{
    _cancelLationToken.Cancel();
}

当我点击 CancelButton 并因此触发 CancelButton_Click 方法时,会触发 CallBack 方法。但是......当我检查 myTaskToWaitFor.IsCanceled 总是返回 false 并且我得到这个信息:Id = 1,Status = RanToCompletion,Method =“{null}”。 为什么状态不是Canceled之类的?

当我使用http://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken.throwifcancellationrequested.aspx

像这样:

private void WorkHard(CancellationToken token)
{
    for(int i = 0; i < 100000000; i++)
        if(token.IsCancellationRequested)
            token.ThrowIfCancellationRequested();
        else
            Math.Acos(Math.Pow(i, i / 10000000));
}

我只在调试模式下遇到一些错误,似乎 myTaskToWaitFor 实际上已取消,但代码没有继续(在继续时,程序由于异常而关闭)。 有什么想法吗? 亲切的问候,

马蒂斯

编辑:

使用 TrowIfCancellationRequested 的测试基于 "当您对已取消的 CancellationToken 调用 ThrowIfCancellationRequested 时, 它会抛出一个 OperationCanceledException。任务并行库知道 这种类型的异常代表取消而不是失败,并将处理 它不同。例如,Task 有一个名为 IsCanceled 的属性,它会自动 当执行异步时抛出 OperationCanceledException 时变为真 方法。”来自 Alex Davies 的 Async in C# 5.0 一书。

这就是为什么我认为我可以期望 myTaskToWaitFor.IsCancelled 返回 true 并且代码将继续。

【问题讨论】:

  • 带有ThrowIfCancellationRequested 的版本是正确的 - 是否有异常行为?不过,预计这会报告一个异常 - 你需要处理它
  • 在检查 myTaskToWaitForGetCashReport.IsCanceled 之前如何处理异常?如果我在“var myTaskToWaitFor = Task.Factory.StartNew(() => WorkHard(_cancelLationToken.Token), _cancelLationToken.Token); await myTaskToWaitFor;”周围添加一个 try catch myTaskToWaitFor 字段是未知的(当然......)。当我还在尝试中添加检查 myTaskToWaitFor.IsCanceled 时...我只去捕获部分。我是否需要在 try 之前创建一个 bool 字段并将其设置在 try 或 catch 中?那是唯一的解决方案吗? (myTaskToWaitFor.IsCanceled(当然)在捕获中是未知的)
  • try / catchawait 周围。到那时该变量是已知的。
  • 啊...听起来是个好主意 ;-) 这就是解决方案。谢谢
  • async 代码as I describe on my blog 中,您应该更喜欢Task.Run 而不是StartNew

标签: c# task async-await cancellationtokensource


【解决方案1】:

ThrowIfCancellationRequested() 是表明您由于观察取消而存在的理想方式。这在调用者处显示为异常,但您可以通过在await 周围添加try / catch 来处理它,并简单地检查那里的原因 - 无论是在任务上,或通过检查AggregateException

【讨论】:

  • 还是个小问题。当我不在 for 循环或类似的东西中使用此解决方案时,而是在这样的代码中设置测试: ct.ThrowIfCancellationRequested();似乎没有抛出异常......这是正确的吗?
  • @user369122 如果您不在循环中,它可能在您取消之前通过了检查...?
  • 不,不是。我实际上做了这样的事情(用于测试): Thread.Sleep(10000); if(ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } 而且我没那么慢 ;-) 达到了投掷线。
猜你喜欢
  • 2013-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多