CancellationToken and CancellationTokenSource-How to use it?

I have a user interface button called Load. It spawns a thread, which in turn spawns a task. Waiting for a task, and if it expires, the task is canceled. The Download button is not disabled, and the user can click on it several times. Each time he clicked on a previous task, it had to be lured.

I am confused about how I should use CancellationTokenSource and CancellationToken here. Beow is a code. Could you suggest how to use it, and are there any problems when using below? No Async, please, since we are not there yet.

CancellationTokenSource _source = new CancellationTokenSource(); public void OnLoad() { //Does this cancel the previously spawned task? _source.Cancel(); _source.Dispose(); _source = new CancellationTokenSource(); var activeToken = _source.Token; //Do I need to do the above all the time or is there an efficient way? Task.Factory.StartNew(() => { var child = Task.Factory.StartNew(() => { Thread.Sleep(TimeSpan.FromSeconds(20)); activeToken.ThrowIfCancellationRequested(); }, activeToken); if (!child.Wait(TimeSpan.FromSeconds(5))) { _source.Cancel(); } }); } 

Note I need to cancel any previously defined tasks, and each unsolved task must have a timeout.

+6
source share
3 answers

First, if you are using Visual Studio 2012+, you can add the Microsoft.Bcl.Async package to add support for async and other advanced features to your .NET 4.0 project.

If you are using Visual Studio 2010, you can use the WithTimeout extension method that comes with the ParallelExtensionsExtras library. The method wraps the original task with a TaskCompletion source and a timer that calls SetCancelled if it expires.

The code is here , but the actual method is simple:

  /// <summary>Creates a new Task that mirrors the supplied task but that /// will be canceled after the specified timeout.</summary> /// <typeparam name="TResult">Specifies the type of data contained in the /// task.</typeparam> /// <param name="task">The task.</param> /// <param name="timeout">The timeout.</param> /// <returns>The new Task that may time out.</returns> public static Task<TResult> WithTimeout<TResult>(this Task<TResult> task, TimeSpan timeout) { var result = new TaskCompletionSource<TResult>(task.AsyncState); var timer = new Timer(state => ((TaskCompletionSource<TResult>)state).TrySetCanceled(), result, timeout, TimeSpan.FromMilliseconds(-1)); task.ContinueWith(t => { timer.Dispose(); result.TrySetFromTask(t); }, TaskContinuationOptions.ExecuteSynchronously); return result.Task; } 

You can use it immediately after creating your task:

 var myTask=Task.Factory.StartNew(()=>{...}) .WithTimeout(TimeSpan.FromSeconds(20)); 

In general, you can create the desired behavior by creating a TaskCompletionSource that calls its SetResult, SetCancelled methods in response to events or criteria you set.

+5
source

This will be done:

  private CancellationTokenSource _cancelTasks; // this starts your process private void DoStuff() { _cancelTasks = new CancellationTokenSource(); var task = new Task(() => { /* your actions here */ }, _cancelTasks.Token); task.Start(); if (!task.Wait(5000)) _cancelTasks.Cancel(); } 
+2
source

There are several errors in your code that make things confusing.

First, you use Thread.Sleep instead of Task.Delay or some other timer-based method (I highly recommend writing your own if you don't have access to Task.Delay). Sleep is a blocking wait and cannot be caused by a cancellation token. The result is that the threads of the threads of the flow of precious objects are held hostage for several seconds, even if the operation is canceled. This may result in later button presses being supported earlier.

Secondly, at the end of the wait, you cancel _source, but this refers to the current value of the source, and not to the value at the time the button is clicked. Previous button presses will override subsequent button press effects instead of their own.

Thirdly, you delete the source of the cancellation token in one thread while you are chasing to cancel it on another. You are lucky that you do not get object-related exceptions.

Fourth, it would be ideal to use async in such a situation. You mentioned that you were only on .Net 4.0.

Fixing the first three things should do what is easier to reason about:

 CancellationTokenSource _prevSource = new CancellationTokenSource(); public void OnButtonPress() { var curSource = new CancellationTokenSource(); _prevSource.Cancel(); _prevSource = curSource; MyCustomDelay(TimeSpan.FromSeconds(5), curSource.Token).ContinueWith(t => { curSource.Cancel(); }, TaskContinuationOptions.OnlyOnRanToCompletion); var r = MyCustomDelay(TimeSpan.FromSeconds(20), curSource.Token).ContinueWith(t => { curSource.ThrowIfCancellationRequested(); }, TaskContinuationOptions.OnlyOnRanToCompletion); // after 5 seconds the token r delay is conditions on is cancelled // so r is cancelled, due to the continuation specifying OnlyOnRanToCompletion // the ThrowIfCancellationRequested line won't be executed // although if we removed the cancel-after-5-seconds bit then it would be } 
0
source

All Articles