Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking Cancellation Tokens

I use a cancellation token that is passed around so that my service can be shut down cleanly. The service has logic that keeps trying to connect to other services, so the token is a good way to break out of these retry loops running in separate threads. My problem is that I need to make a call to a service which has internal retry logic but to return after a set period if a retry fails. I would like to create a new cancellation token with a timeout which will do this for me. The problem with this is that my new token isn't linked to the “master” token so when the master token is cancelled, my new token will still be alive until it times-out or the connection is made and it returns. What I would like to do is link the two tokens together so that when the master one is cancelled my new one will also cancel. I tried using the CancellationTokenSource.CreateLinkedTokenSource method but when my new token timed-out, it also cancelled the master token. Is there a way to do what I need to do with tokens or will it require changes to the retry logic (probably not going to be able to do this easily)

Here is what I want to do:

Master Token – passed around various functions so that the service can shut down cleanly. Temporary Token – passed to a single function and set to timeout after one minute

If the Master Token is cancelled, the Temporary Token must also be cancelled.

When the Temporary Token expires it must NOT cancel the Master Token.

like image 937
Retrocoder Avatar asked Apr 14 '15 08:04

Retrocoder


People also ask

How do you handle a cancellation token?

The wait handle of the cancellation token will become signaled in response to a cancellation request, and the method can use the return value of the WaitAny method to determine whether it was the cancellation token that signaled. The operation can then just exit, or throw a OperationCanceledException, as appropriate.

Can a cancellation token be reused?

CancellationTokenSource is quite a heavyweight object and its not normally cancelled; however it can't be pooled or reused because its registrations cannot be cleared.

Should cancellation token source be disposed?

Always call Dispose before you release your last reference to the CancellationTokenSource. Otherwise, the resources it is using will not be freed until the garbage collector calls the CancellationTokenSource object's Finalize method.

What is cancellation token source?

A CancellationTokenSource object, which provides a cancellation token through its Token property and sends a cancellation message by calling its Cancel or CancelAfter method. A CancellationToken object, which indicates whether cancellation is requested.


2 Answers

You want to use CancellationTokenSource.CreateLinkedTokenSource. It allows to have a "parent" and a "child" CancellationTokenSourcees. Here's a simple example:

var parentCts = new CancellationTokenSource(); var childCts = CancellationTokenSource.CreateLinkedTokenSource(parentCts.Token);  childCts.CancelAfter(1000); Console.WriteLine("Cancel child CTS"); Thread.Sleep(2000); Console.WriteLine("Child CTS: {0}", childCts.IsCancellationRequested); Console.WriteLine("Parent CTS: {0}", parentCts.IsCancellationRequested); Console.WriteLine();  parentCts.Cancel(); Console.WriteLine("Cancel parent CTS"); Console.WriteLine("Child CTS: {0}", childCts.IsCancellationRequested); Console.WriteLine("Parent CTS: {0}", parentCts.IsCancellationRequested); 

Output as expected:

Cancel child CTS
Child CTS: True
Parent CTS: False

Cancel parent CTS
Child CTS: True
Parent CTS: True

like image 97
i3arnon Avatar answered Oct 04 '22 06:10

i3arnon


If all you have is a CancellationToken, instead of a CancellationTokenSource, then it is still possible to create a linked cancellation token. You would simply use the Register method to trigger the cancellation of the the (pseudo) child:

var child = new CancellationTokenSource(); token.Register(child.Cancel); 

You can do anything you would typically do with a CancellationTokenSource. For example you can cancel it after a duration and even overwrite your previous token.

child.CancelAfter(cancelTime); token = child.Token; 
like image 29
John Gietzen Avatar answered Oct 04 '22 05:10

John Gietzen