How to reset a CancellationToken properly?

36,076

Solution 1

You need to recreate the CancellationTokenSource - there is no way to "reset" this once you set it.

This could be as simple as:

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (button.Content == "Start")
    {
        button.Content = "Stop";
        cts.Dispose(); // Clean up old token source....
        cts = new CancellationTokenSource(); // "Reset" the cancellation token source...
        DoWork(cts.Token);
    }
    else
    {
        button.Content = "Start";
        cts.Cancel();
    }
}

Solution 2

I had the same problem and I figured it out that the best way to solve it is to create cancellation token source newly just before calling the method.

this is what I do on my start button click:

cancellationTokenSource = new CancellationTokenSource();
cancellationToken = cancellationTokenSource.Token;
Task.Factory.StartNew(StartUpload, cancellationToken);

I change the caption for the same button to cancel and when a click occurs on cancel, I call

cancellationTokenSource.Cancel();

Here is the full code:

if (button3.Text != "&Start Upload")
{
    cancellationTokenSource.Cancel();
}
else
{
    try
    {
        cancellationTokenSource = new CancellationTokenSource();
        cancellationToken = cancellationTokenSource.Token;
        Task.Factory.StartNew(StartUpload, cancellationToken);
    }
    catch (AggregateException ex)
    {
        var builder = new StringBuilder();
        foreach (var v in ex.InnerExceptions)
            builder.Append("\r\n" + v.InnerException);
        MessageBox.Show("There was an exception:\r\n" + builder.ToString());
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Solution 3

Now, with .NET 6 you can use TryReset() method which Attempts to reset the CancellationTokenSource to be used for an unrelated operation. see this issue and CancellationTokenSource.cs for more details.

Share:
36,076
poco
Author by

poco

Updated on July 05, 2022

Comments

  • poco
    poco almost 2 years

    I have been playing round with the Async CTP this morning and have a simple program with a button and a label. Click the button and it starts updating the label, stop the button it stops writing to the label. However, I'm not sure how to reset the CancellationTokenSource so that I can restart the process.

    My code:

    public partial class MainWindow : Window
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        public MainWindow()
        {
            InitializeComponent();
            button.Content = "Start";
        }
    
        async Task DoWork(CancellationToken cancelToken)
        {
            int i = 0;
            while (!cancelToken.IsCancellationRequested)
            {
                label.Content = i++.ToString();
                await TaskEx.Delay(50, cancelToken);
            }
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (button.Content == "Start")
            {
                button.Content = "Stop";
                DoWork(cts.Token);
            }
            else
            {
                button.Content = "Start";
                cts.Cancel();
            }
        }
    }
    
  • Zerowalker
    Zerowalker over 10 years
    When are you supposed to dispose of it on close of the application? As you have to wait before the Thread is done, else you get ObjectDisposed exception.
  • Reed Copsey
    Reed Copsey over 10 years
    @user2587718 It really depends on what type of object, etc. I'd recommend asking your own question regarding this.
  • Louis Duran
    Louis Duran about 6 years
    Should really do a null check before disposing but this was good since it is exactly what I am doing.
  • User1
    User1 over 4 years
    Trying to learn abit more about CancellationTokens, Why are you not disposing of the cts straight after the Cancel call? Should it only be disposed of the next time it is about to be newed up?