23 Ekim 2013 Çarşamba

Cancel an Asynchronous Method [C#]

Sponsorlu Bağlantılar
This example shows how to implement support for asynchronous method cancellation in your class. It is based on the Create an Asynchronous Method example.
This example is part of asynchronous method implementation series.
We implement a CancelAsync method that signals the asynchronous worker to cancel the operation. This is done by setting a boolean variable that is periodically checked by the asynchronous worker. When the asynchronous worker receives the cancel signal, it finishes and fires the MyTaskCompleted event with the Cancelled flag set.

MyAsyncContext class

To signal the worker, we need an object with a boolean property. This property will be set by the CancelAsync method and periodically checked by the asynchronous worker.
[C#]
internal class MyAsyncContext
{
  private readonly object _sync = new object();
  private bool _isCancelling = false;

  public bool IsCancelling
  {
    get
    {
      lock (_sync) { return _isCancelling; }
    }
  }

  public void Cancel()
  {
    lock (_sync) { _isCancelling = true; }
  }
}

We add a member of the MyAsyncContext type to our class.
[C#]
private MyAsyncContext _myTaskContext = null;

This member is set in the MyTaskAsync method when the asynchronous operation is invoked. The same MyAsyncContext instance is passed also to the asynchronous worker.
[C#]
public void MyTaskAsync(string[] files)
{
  MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(MyTaskWorker);
  AsyncCallback completedCallback = new AsyncCallback(MyTaskCompletedCallback);

  lock (_sync)
  {
    if (_myTaskIsRunning)
      throw new InvalidOperationException("The control is currently busy.");

    AsyncOperation async = AsyncOperationManager.CreateOperation(null);
    MyAsyncContext context = new MyAsyncContext();
    bool cancelled;

    worker.BeginInvoke(files, context, out cancelled, completedCallback, async);

    _myTaskIsRunning = true;
    _myTaskContext = context;
  }
}

private readonly object _sync = new object();

Asynchronous code modifications

The asynchronous worker must be modified to support cancellation. As you could notice in MyTaskAsync code, we added one input parameter of type MyAsyncContext and one output boolean parameter. The latter one indicates, whether the operation has been cancelled, when the worker finishes.
[C#]
private void MyTaskWorker(string[] files, MyAsyncContext asyncContext,
  out bool cancelled)
{
  cancelled = false;

  foreach (string file in files)
  {
    // a time consuming operation with a file (compression, encryption etc.)
    Thread.Sleep(1000);

    if (asyncContext.IsCancelling)
    {
      cancelled = true;
      return;
    }
  }
}

private delegate void MyTaskWorkerDelegate(string[] files,
  MyAsyncContext asyncContext, out bool cancelled);

The worker periodically test the asyncContext.Is­Cancelling property. If the property is set to true, the output parameter cancelled is set and the method is finished.
The value of the cancelled parameter is copied to the AsyncComplete­dEventArgs.Can­celledproperty in asynchronous operation completed callback.
[C#]
private void MyTaskCompletedCallback(IAsyncResult ar)
{
  // get the original worker delegate and the AsyncOperation instance
  MyTaskWorkerDelegate worker =
      (MyTaskWorkerDelegate)((AsyncResult)ar).AsyncDelegate;
  AsyncOperation async = (AsyncOperation)ar.AsyncState;
  bool cancelled;

  // finish the asynchronous operation
  worker.EndInvoke(out cancelled, ar);

  // clear the running task flag
  lock (_sync)
  {
    _myTaskIsRunning = false;
    _myTaskContext = null;
  }

  // raise the completed event
  AsyncCompletedEventArgs completedArgs = new AsyncCompletedEventArgs(null,
    cancelled, null);
  async.PostOperationCompleted(
    delegate(object e) { OnMyTaskCompleted((AsyncCompletedEventArgs)e); },
    completedArgs);
}

CancelAsync method

This method signals the asynchronous worker to cancel the operation. It uses the MyAsyncContext instance that was created during asynchronous operation invokation.
[C#]
public void CancelAsync()
{
  lock (_sync)
  {
    if (_myTaskContext != null)
      _myTaskContext.Cancel();
  }
}

Note: If you have only one asynchronous method in your class, consider renaming the CancelAsync method to a name similar to MyTaskAsyncCan­cel. All the asynchronous operation related methods will then be displayed together in Visual Studio.

In this series

  1. [C#] Create an Asynchronous Method – how to create an asynchronous method
  2. [C#] Asynchronous Method Progress Reporting – how to report progress
  3. [C#] Cancel an Asynchronous Method – implement cancellation support
Sponsorlu Bağlantılar

Hiç yorum yok:

Yorum Gönder