3

我无法停止任务。首先,我刚开始使用Tasks。以前,我一直使用 delegate.BeginInvoke() 在后台运行,但这次我需要停止后台执行,如果需要的话。所以我切换到任务。这是我的代码:

CancellationTokenSource token = new CancellationTokenSource();
Task posting = Task.Factory.StartNew(() => DoPosting(docs, session), token.Token);
HttpRuntime.Cache[session.ToString() + "_token"] = token;
HttpRuntime.Cache[session.ToString() + "_task"] = posting;

这是 ASP.NET MVC,所以我将持久的东西存储在 HttpRuntime.Cache 中。用户可以通过此操作取消操作:

public JsonResult StopPosting(string session)
{
    CancellationTokenSource token = (CancellationTokenSource)HttpRuntime.Cache.Get(session.ToString() + "_token");
    Task posting = (Task)HttpRuntime.Cache[session.ToString() + "_task"];
    token.Cancel();

    return Json(new { Message = "Stopped!" });
}

现在,当这个动作第一次被击中时,什么也没有发生。然后我第二次要求取消。现在,token.IsCancellationRequested 说“真”,所以 token.Cancel() 一定做了什么。但是posting.Status 仍然是“正在运行”。它会一直保持这种状态,直到它完成,然后它是“RunToCompletion”。

所以,我要求取消一个任务,但它没有被取消。

也许我做错了什么或者我遗漏了一些明显的东西,但我只是看不到/理解为什么它不会取消。

也许有人可以解释一下?

问候。

4

2 回答 2

7

取消令牌不会立即导致任务的委托停止执行。支持这一点(如Abort通过线程完成)可能会导致各种不良情况,包括未正确清理对象、由于执行停止在逻辑上应该被视为原子的操作的中途停止而违反不变量等。

您需要做的是让正在执行的实际函数查看 CancellationToken 并定期验证它是否未被取消。除了将令牌传递给StartNew您还需要将其传递给DoPosting方法。然后,如果确实请求取消,则该方法需要定期调用token.ThrowIfCancellationRequested();该方法中适合停止的位置。

请参阅如何取消不可取消的异步操作?供进一步阅读。

于 2013-06-06T16:29:00.073 回答
2

我认为您可能对 CancellationToken 期望过高。至于任务,我认为 CancellationToken 仅在确定是否在任务可用插槽时启动任务时使用。一旦任务启动,任务框架就不能在取消 CancellationToken 时简单地中止委托调用。为了完全取消这样的事情,必须编写由任务框架 (DoPosting) 调用的代码以了解 CancellationToken,并且必须直接在代码中的适当位置检查该令牌的状态。

于 2013-06-06T16:28:57.230 回答