【问题标题】:Proper way of cancel execution of a method [duplicate]取消方法执行的正确方法[重复]
【发布时间】:2012-11-09 02:12:52
【问题描述】:

可能重复:
How do I abort/cancel TPL Tasks?

我有一个需要一些时间来执行的方法,因此我将结果作为回调返回。我的方法如下:

public static void DoWork( Action<object> onCompleteCallBack)
{
  Task.Factory.StartNew( () => {
    // Do work
    onCompleteCallBack(someResult);
  });
}

现在我希望能够停止执行该方法,以防用户不想等待。结果,这就是我所制定的:

static void Main ( string[] args )
{            
  var cancelMethod = DoWork( x =>
  {                
    // method completed
    Console.Write( x.ToString() );
  });
  Thread.Sleep( 5000 ); // some time passes 

  // then user decides to abort method
  cancelMethod();
  Console.Read();
}

static Action DoWork ( Action<object> onCompleteCallBack )
{
  bool stopExecuting = false;
  Task.Factory.StartNew( () =>
  {
    for ( var i = 0 ; i < 100000 ; i++ ) 
    {
      Thread.Sleep( 1 );
      if ( stopExecuting )
      {
        onCompleteCallBack( "Method aborted!" );
        return;
      }
    }         
    onCompleteCallBack( "Method completed successfully" );
  } );
  return () => { stopExecuting = true; };
}

中止方法执行的更合适的方法是什么?

编辑

感谢您的回答。我现在记得取消令牌的事情。象征性的东西很难记住。我想我会使用这种方法:

    static void Main ( string[ ] args )
    {
        Action abortTask;

        DoWork( methodCompleted, out abortTask );

        Thread.Sleep( 5000 ); // some time passes then user decides to abort method

        // cancel execution of method
        abortTask( );

        Console.Read( );
    }

    static void methodCompleted ( object msg )
    {            
        Console.Write( msg.ToString( ) );  
    }

    static void DoWork ( Action<object> onCompleteCallBack, out Action abortThisTask )
    {
        bool stopExecuting = false;

        abortThisTask = ( ) => { stopExecuting = true; };

        Task.Factory.StartNew( ( ) =>
        {
            for ( var i = 0 ; i < 100000 ; i++ ) 
            {
                Thread.Sleep( 1 );

                if ( stopExecuting )
                {
                    onCompleteCallBack( "Method aborted!" );
                    return;
                }
            }

            onCompleteCallBack( "Method completed successfully" );
        } );            
    }

    // Overloaded method
    static void DoWork ( Action<object> onCompleteCallBack )
    {
        Action abortTask;
        DoWork( onCompleteCallBack ,out abortTask );
    }

使用你们在这个问题的答案中建议的方法与这种方法相比会更好吗?我更喜欢这种方法。我认为它比取消令牌更容易阅读。

PS。 我的 Visual Studio 放置了很多空间。随意格式化代码:)

【问题讨论】:

  • 感谢您提供的链接,我将尝试关闭我正在寻找的答案。

标签: c# task-parallel-library abort cancellation


【解决方案1】:

通过在任务中指定您的函数来尝试使用取消令牌 http://blogs.msdn.com/b/csharpfaq/archive/2010/07/19/parallel-programming-task-cancellation.aspx

CancellationTokenSource tokenSource = new CancellationTokenSource();
 Task.Factory.StartNew( () => {
    // Do work
    onCompleteCallBack(someResult);
  }, tokenSource.Token);

private void cancel_Click(object sender, RoutedEventArgs e)
{
    tokenSource.Cancel();

}

【讨论】:

    【解决方案2】:

    CancellationTokenAlbahari's guide安全取消线程

    【讨论】:

      【解决方案3】:

      存在接受 CancellationToken 的 StartNew() 方法的重载。这是一个示例:http://msdn.microsoft.com/en-us/library/dd997396.aspx。基础是您创建然后将此令牌传递给您的方法(或从父线程引用它;它是线程安全的)。然后,您的并行方法必须在方便的时候(例如在循环中)检查令牌是否指示任务已被取消。如果是这样,它会优雅地退出。

      【讨论】:

        【解决方案4】:

        任务允许您传递CancellationToken。您可以调用 ct.Cancel() 以设置取消标志。在您的实际执行逻辑中,您可以在某些“检查点”添加检查以测试 if (ct.IsCancellationRequested) 并从那里返回方法或调用 ct.ThrowIfCancellationRequested()

        【讨论】:

        • ThrowIfCancellationRequested 的意义何在?我知道这种方法来自 MSDN,但为什么不只是 Throw New UserCancellationException 或任何适用的方法?
        • 我不太确定,因为我自己对此很陌生;我只是分享我学到的东西。就个人而言,我只是返回不同的东西而不是抛出异常。一般来说,抛出异常的好处是在异常处理程序中有清理逻辑。
        • 我也在学习,但没听说过ThrowIfCancellationRequested。如果您解释它可以提供的好处,特别是关于 MSDN 上描述的上下文,我会亲自给您一个 +1 的答案。 :)
        • This answer 很有趣。看起来像 ThrowIfCancellationRequested = if (token.IsCancellationRequested) throw new OperationCanceledException(token);,尽管后者更具可读性,即您清楚地看到抛出的异常类型。
        • 在我看来,OperationCanceledExceptionUserCancellationException 之间的区别在于它们派生自哪些类以及它们的用途。根据 MSDN 文档,“当用户在 GetToken(CardSpacePolicyElement[], SecurityTokenSerializer) 调用期间取消操作时”会抛出 UserCancellationException。该方法位于 System.IdentityModel.Selectors 命名空间中,而 OperationCanceledException 派生自 System.Exception 并且还包含被取消的原始 CancellationToken
        【解决方案5】:

        http://msdn.microsoft.com/en-us/library/dd537607(v=vs.100).aspx 可能是一个不错的起点。取决于你的目标。

        【讨论】:

        猜你喜欢
        • 2011-03-12
        • 1970-01-01
        • 2020-02-27
        • 2016-02-22
        • 2018-05-30
        • 1970-01-01
        • 2011-04-15
        • 2011-02-13
        • 2019-09-20
        相关资源
        最近更新 更多