Search code examples
c#winformsasynchronousasync-awaitcancellation

Cancel async and await method in C#


I have an asynchronous call in C# and I'm trying to implement a cancellation logic. I searched around the Internet but I couldn't find a solution for my issue.

I have a Windows Forms with a Start button, a Cancel button and a textbox to show the results. Following code:

private CancellationTokenSource _cancelSource;
private CancellationToken _token;

private void btnStart_Click(object sender, EventArgs e)
{
  DisplayPrimeCountsAsync(_token);
}

private async void DisplayPrimeCountsAsync(CancellationToken token)
{
   btnStart.Enabled = false;

   for (int i = 0; i < 100; i++)
   {
     textBox1.Text += await GetPrimesCountAsync(i*1000000 + 2, 1000000, token) + Environment.NewLine;
   }

    btnStart.Enabled = true;
 }

 private Task<int> GetPrimesCountAsync(int start, int count, CancellationToken token)
 {
    return
       Task.Run(() =>
           ParallelEnumerable.Range(start, count).Count(n =>
              Enumerable.Range(2, (int) Math.Sqrt(n) - 1).All(i => n%i > 0)), token);
  }

private void btnCancel_Click(object sender, EventArgs e)
{
  _cancelSource = new CancellationTokenSource();
  _token = _cancelSource.Token;
  _cancelSource.Cancel();
  btnCancel.Enabled = false;
 }

Now this is not getting cancelled at all. I have found following piece of code:

 if (token.IsCancellationRequested) 
 {
   token.ThrowIfCancellationRequested();
 }

but I don't know where to put this in. Tried to put this and the prime numbers linq expression into another method and call this method over Task.Run but nothing helps. Can someone show me how to implement this cancellation logic the right way? Thanks in advance!


Solution

  • Did you try to call the following code before launching your task?

    _cancelSource = new CancellationTokenSource();
    _token = _cancelSource.Token;
    

    Feels like when you launch your task the token is null and you set it afterward. (didn't try it though)

    Of course in this case you have to remove the same code from your cancel method.