Home > Enterprise >  Cancelation token waits entire delay duration before cancelling
Cancelation token waits entire delay duration before cancelling

Time:02-20

In the following code, if the UserCancelled property is set to true, I want it to end the loop immediately and continue code.

The problem I'm facing is it continues after the 6 seconds passes, not before, which I thought the cancellation token would end the delay early.

What are the options to end this delay sooner?

CancellationTokenSource _source = new CancellationTokenSource();
var token = _source.Token;
foreach (var mock in lst)
{
    if (UserCancelled)
    {
       _source.Cancel();
       _source.Dispose();
       break;
    }
    
       label1.Text = mock.Name;
       await Task.Delay(6000, token);
                    
 }
    
 label1.Text  = " Broke Out";

CodePudding user response:

It's because the cancellation is not requested until the continuation is executed after waiting for 6 seconds. Extract the cancellation source into a field and call _source.Cancel() at the moment you set UserCancelled to true.

label1 gives me the hint this is some sort of UI code so I would refactor it something like this:

// this is a field
private CancellationTokenSource _source = new CancellationTokenSource();

// call this from whatever handler/command and pass _source.Token to it:
private async Task DoMyTaskAsync(CancellationToken token)
{
    foreach (var mock in lst)
    {
        if (token.IsCancellationRequested)
            break;
    
       label1.Text = mock.Name;
       await Task.Delay(6000, token);                    
     }
    
     label1.Text  = " Broke Out";
}

// can be a simple event handler, too (eg. for some btnCancel.Click)
private void OnCancelCommand()
{
    // avoid double cancellation and ObjectDisposedException
    if (UserCancelled)
        return;
    _source.Cancel();
    _source.Dispose();
    UserCancelled = true;
}

CodePudding user response:

If UserCancelled is already set to true when we enter the loop, then you should cancel immediately.

If UserCancelled was false on initial check then you go to the Task.Delay and start waiting. No any additional checks are performed during the wait.

After 60s the work resumes and you go on then next iteration of the loop. And here, again, if f UserCancelled is set to true, you will cancel and exit, else will wait for another 60s.

The best solution here will be to make the _source variable available to the code, which is setting UserCancelled. And such a code will call _source.Cancel() directly.

  • Related