Search code examples
c#task-parallel-libraryabortcancellation

Proper way of cancel execution of a method


Possible Duplicate:
How do I abort/cancel TPL Tasks?

I have a method that takes some time to execute therefore I return the result as a callback. My method looks like:

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

Now I will like to be able to stop executing that method in case the user does not want to wait. As a result this is what I have worked out:

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

What will be a more appropriate way of aborting the execution of a method?

Edit

Thanks for your answers. I remember now about the cancellation token thing. The token thing is hard to remember. I think I will use this approach:

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

Will it be better to use the approaches you guys suggested on the answers to this question vs. This approach. I like this approach better. I think it is easier to read than the cancellation token one.

PS. My Visual Studio places a lot of spaces. Feel free to format the code :)


Solution

  • try using cancellation token by specifying it your function in task 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();
    
    }