nop
nop

Reputation: 6359

Being able to reuse same CancellationTokenSource - CancellationTokenSource.CreateLinkedTokenSource

I'm trying to figure out what CancellationTokenSource.CreateLinkedTokenSource actually does. I know it's a regular cancellation source that is also "linked" to an existing token.

The following snippet does the following:

It's actually reusing same cts instance over and over again. Is that behavior coming from CancellationTokenSource.CreateLinkedTokenSource? I mean when a CancellationTokenSource is canceled, I shouldn't be able to use it again, unless I create a new one instead.

If that's the case, why does the snippet pass a CancellationToken to the Start method, when we never actually cancel the cts, but the linked one?

// Program.cs
var cts = new CancellationTokenSource();

await foreach (var item in items.Start(cts.Token))
{
    Console.WriteLine(item);
    item.Stop();
    item.Start(cts.Token);
}
private CancellationTokenSource? _cts;

public IAsyncEnumerable<string> Start(CancellationToken cancellationToken)
{
    _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

    ...
}

public void Stop()
{
    _cts?.Cancel();
}

Upvotes: 3

Views: 3383

Answers (2)

Yordan Voyvode
Yordan Voyvode

Reputation: 53

You cant Re-use the same CancellationTokenSource you need to Dispose() it when you finished using it to not get Memory leak if you use that part of the code a lot and make a new Instance of the CancellationTokenSource before the part that you have to use it. Once a CancellationTokenSource has been canceled, it cannot be reset or reused. You usually just set the CancellationTokenSource cancelSourceT; in the Class level field without making new() instance of it and then instantiate it before the part that you have to use it. The reason is that: isCancellationRequested property of the CancellationTokenSource stays True after you .Cancel() the token and if you try to use it its just gonna keep Raising TaskCanceledException on the part that you just want to cancel once Example:

if (xInput[i] != -1 || yInput[i] != -1)
                {
                    //int pickedRNG=randomNumberGenerator.Next(300, 601);
                    int delayMiliseconds = int.Parse(listPanelLabelsCords[i].delayBox.Text);
                    try
                    {
                        await Task.Delay(delayMiliseconds, cancelToken);//<--It will keep Raising Exceptions from the First Cancel()-ed Token since isCancellationRequired is still True from the Cancel() method and you cant ReSet it(you can check this when Debugging when you hover over the TokenSource variable you created and expand the Filed list)
                    }
                    catch (TaskCanceledException)
                    {
                        break;
                    }
                    ClickAtClass.ClickAt(xInput[i], yInput[i]); //<---This part of the code will Not be reached ever (Except the first time you Cancel())if you instantiate the TokenSource at class field level
                }

Upvotes: 2

Karen Payne
Karen Payne

Reputation: 5157

Once Cancel() is issued and you want to reuse the CancellationTokenSource perform a check via IsCancellationRequested, if true than Dispose _cts and recreate _cts.

if (_cts.IsCancellationRequested)
{
    _cts.Dispose();
    _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
}

Upvotes: 2

Related Questions