CodeJunkie
CodeJunkie

Reputation: 13

CancellationTokenSource does not cancel the task

I have Two button for scenarios where one initiate the task and other stop that task.

   // this is the property which is used to cancel the task
   CancellationTokenSource cTokenSource;

private async void OnReadCommand()
{
   cTokenSource = new CancellationTokenSource();
   ReadAction();
}


private async void ReadAction()
{
   Task.Factory.StartNew(() => {
       while (true)
       {
           Task.Delay(TimeSpan.FromSeconds(2)).Wait();
        //writing in debug console
           Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
        //sending it to the ui for testing
           uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
       }
   },cTokenSource.Token);
}
       
private async void OnCancelCommand()
{
   // it's used to cancel the task
   cTokenSource.Cancel();
}

my app is wpf and using mvvm pattern and prism library. while calling the OnCancelCommand the task is running in background and printing the GUID. I have to cancel the task only and only on OnCancelCommand.

Upvotes: 1

Views: 737

Answers (1)

mr100
mr100

Reputation: 4428

You need to implement the code for exiting the loop yourself:

private async void ReadAction()
{
    Task.Factory.StartNew(() => {
        while (true)
        {
            Task.Delay(TimeSpan.FromSeconds(2)).Wait();
            //writing in debug console
            Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
            //sending it to the ui for testing
            uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
            
            cTokenSource.Token.ThrowIfCancellationRequested();
        }
    },cTokenSource.Token);
}

or

private async void ReadAction()
{
    Task.Factory.StartNew(() => {
        while (true)
        {
            Task.Delay(TimeSpan.FromSeconds(2)).Wait();
            //writing in debug console
            Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
            //sending it to the ui for testing
            uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
            
            if (cTokenSource.Token.IsCancellationRequested)
            {
                break; // or return;
            }
        }
    },cTokenSource.Token);

Usage examples you can find in the documenation Task Class. The only benefit that you get from passing CancellationToken to StartNew method is that it can automatically cancel the task for you if the source is cancelled before the task started. However to cancel it during the run you need to code the logic yourself. Here is another good reading on that https://stackoverflow.com/questions/48312544/whats-the-benefit-of-passing-a-cancellationtoken-as-a-parameter-to-task-run#:~:text=In%20summary%2C%20providing%20the%20cancellation,to%20start%20running%20the%20task.

Furthermore, I would suggest to you using await in the logic that you execute in StartNew so that you do not loose the benefits of being asynchronous:

private async void ReadAction()
{
    Task.Factory.StartNew(async () => {
        while (true)
        {
            await Task.Delay(TimeSpan.FromSeconds(2));
            //writing in debug console
            Debug.WriteLine($"Some Random Nos : {Guid.NewGuid().ToString()}");
            //sending it to the ui for testing
            uiContext.Send(x => MessageArea2Content.Message = Guid.NewGuid().ToString(), null);
            
            if (cTokenSource.Token.IsCancellationRequested)
            {
                break; // or return;
            }
        }
    },cTokenSource.Token)

That way threads will no longer get blocked and will be released during a call to Delay.

Upvotes: 1

Related Questions