Is there a way I can cause a running method to stop immediately with a cts.Cancel();

你说的曾经没有我的故事 提交于 2020-12-21 03:52:39

问题


I have code that creates a CancellationTokenSource and that passes it to a method.

I have code in another are of the app that issues a cts.Cancel();

Is there a way that I can cause that method to stop immediately without me having to wait for the two lines inside the while loop to finish?

Note that I would be okay if it caused an exception that I could handle.

public async Task OnAppearing()
{
   cts = new CancellationTokenSource();
   await GetCards(cts.Token);
}

public async Task GetCards(CancellationToken ct)
{
   while (!ct.IsCancellationRequested)
   {
      App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts);
      await CheckAvailability();
   }
}

回答1:


What I can suggest:

  1. Modify GetViewablePhrases and CheckAvailability so you could pass the CancellationToken to them;
  2. Use ct.ThrowIfCancellationRequested() inside these functions;
  3. Try / Catch the OperationCanceledException inside GetCards;

As for your your functions I don't know how exactly they work inside. But let's assume you have a long running iteration inside one of them:

CheckAvailability(CancellationToken ct)
{
    for(;;) 
    {
        // if cts.Cancel() was executed - this method throws the OperationCanceledException
        // if it wasn't the method does nothing
        ct.ThrowIfCancellationRequested(); 
        ...calculations... 
    } 
}

Or let's say you are going to access your database inside one of the function and you know that this process is going to take a while:

CheckAvailability(CancellationToken ct)
{
    ct.ThrowIfCancellationRequested();
    AccessingDatabase();
}

This will not only prevent your functions from proceeding with execution, this also will set the executioner Task status as TaskStatus.Canceled

And don't forget to catch the Exception:

public async Task GetCards(CancellationToken ct)
{
   try
   {
      App.viewablePhrases = App.DB.GetViewablePhrases(Settings.Mode, Settings.Pts, ct);
      await CheckAvailability(ct);
   }
   catch(OperationCanceledException ex)
   {
       // handle the cancelation...
   }
   catch
   {
       // handle the unexpected exception
   }
}



回答2:


If you are OK with cancelling not the task, but the awaiting of the task, you could use a cancelable wrapper. In case of cancellation the underlying task will continue running, but the wrapper will complete immediately as canceled.

public static Task AsCancelable(this Task task,
    CancellationToken cancellationToken)
{
    var cancelable = new Task(() => { }, cancellationToken);
    return Task.WhenAny(task, cancelable).Unwrap();
}

public static Task<T> AsCancelable<T>(this Task<T> task,
    CancellationToken cancellationToken)
{
    var cancelable = new Task<T>(() => default, cancellationToken);
    return Task.WhenAny(task, cancelable).Unwrap();
}

Usage example:

await GetCards(cts.Token).AsCancelable(cts.Token);

This extension method can also be implemented using a TaskCompletionSource<T> (instead of the Task<T> constructor).



来源:https://stackoverflow.com/questions/59243161/is-there-a-way-i-can-cause-a-running-method-to-stop-immediately-with-a-cts-cance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!