【问题标题】:Does Task.Wait(int) stop the task if the timeout elapses without the task finishing?如果超时没有完成任务,Task.Wait(int) 会停止任务吗?
【发布时间】:2010-10-27 17:59:09
【问题描述】:

我有一个任务,我希望它需要不到一秒钟的时间来运行,但如果它需要的时间超过几秒钟,我想取消该任务。

例如:

Task t = new Task(() =>
        {
            while (true)
            {
                Thread.Sleep(500);
            }
        });
t.Start();
t.Wait(3000);

请注意,3000 毫秒后等待到期。超时后任务被取消还是任务仍在运行?

【问题讨论】:

标签: c# .net multithreading task-parallel-library task


【解决方案1】:

Task.Wait() 等待 指定的时间来完成任务并返回任务是否在指定的时间量(或更早)内完成。任务本身不被修改,不依赖等待。

阅读精彩系列:Parallelism in .NETParallelism in .NET – Part 10, Cancellation in PLINQ and the Parallel class,作者 Reed Copsey

还有:.NET 4 Cancellation Framework / Parallel Programming: Task Cancellation

检查以下代码:

var cts = new CancellationTokenSource();

var newTask = Task.Factory.StartNew(state =>
                           {
                              var token = (CancellationToken)state;
                              while (!token.IsCancellationRequested)
                              {
                              }
                              token.ThrowIfCancellationRequested();
                           }, cts.Token, cts.Token);


if (!newTask.Wait(3000, cts.Token)) cts.Cancel();

【讨论】:

  • 我注意到cts.Token 也被传递给Wait() 方法。我在 Microsoft 的文档中找到了一条注释:“将 cancelToken 对象传递给此方法只是允许根据某些条件取消等待。” msdn.microsoft.com/en-us/library/dd321457%28v=vs.110%29.aspx
  • 最后一行可以看起来更漂亮,像这样:cts.CancelAfter(3000); newTask.Wait(cts.Token);
【解决方案2】:

如果要取消Task,则应在创建任务时传入CancellationToken。这将允许您从外部取消Task。如果需要,您可以将取消绑定到计时器。

要使用取消令牌创建任务,请参见以下示例:

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

var t = Task.Factory.StartNew(() => {
    // do some work
    if (token.IsCancellationRequested) {
        // Clean up as needed here ....
    }
    token.ThrowIfCancellationRequested();
}, token);

tokenSource 上取消Task 呼叫Cancel()

【讨论】:

  • 这不允许您“从外部”仅请求取消吗?是否关注基于令牌的请求并实际抛出或继续工作而不取消是否取决于委托?
  • 正确,委托通过检查属性上的IsCancellationRequest来决定是否对请求采取行动。
【解决方案3】:

任务仍在运行,直到您明确告诉它停止或循环完成(这永远不会发生)。

您可以查看 Wait to see this 的返回值:

(来自http://msdn.microsoft.com/en-us/library/dd235606.aspx) 返回值

类型:System.Boolean 如果任务在分配的时间内完成执行,则为 true;否则为假。

【讨论】:

    【解决方案4】:

    超时后任务被取消还是任务仍在运行?

    不是和是。

    传递给Task.Wait 的超时用于Wait,而不是任务。

    【讨论】:

    • 这很有趣,因为这里的帮助文本似乎相反:msdn.microsoft.com/en-us/library/dd270644(v=vs.110).aspx 说,“等待任务在指定的毫秒数内完成执行。” 不确定我是否明白这一点。
    • @Michael 如果传递给Wait 的时间到期,即使任务尚未完成,它也会返回。在这种超时情况下,任务将继续执行直到它完成(并且稍后的Wait 将因此返回完成)。
    【解决方案5】:

    如果您的任务调用任何同步方法来执行任何类型的 I/O 或其他需要时间的未指定操作,那么没有通用的方法可以“取消”它。

    根据您尝试“取消”它的方式,可能会发生以下情况之一:

    • 操作实际上被取消了,它所处理的资源处于稳定状态(你很幸运!)
    • 操作实际上被取消了,它所处理的资源处于不一致的状态(以后可能会导致各种问题)
    • 该操作继续进行,并可能干扰您的其他代码正在执行的任何操作(以后可能会导致各种问题)
    • 操作失败或导致您的进程崩溃。
    • 你不知道会发生什么,因为它没有记录

    在一些有效的场景中,您可以并且可能应该使用其他答案中描述的通用方法之一取消任务。但是如果你在这里是因为你想中断一个特定的同步方法,最好查看那个方法的文档,看看是否有办法中断它,是否有“超时”参数,或者是否有可中断的变化。

    【讨论】:

      猜你喜欢
      • 2014-08-20
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多