Compared to the preceding code for class RulyCanceler, I wanted to run code using CancellationTokenSource
.
How do I use it as mentioned in Cancellation
@BrainSlugs83
You shouldn't blindly trust everything posted on stackoverflow. The comment in Jens code is incorrect, the parameter doesn't control whether exceptions are thrown or not.
MSDN is very clear what that parameter controls, have you read it? http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx
If
throwOnFirstException
is true, an exception will immediately propagate out of the call to Cancel, preventing the remaining callbacks and cancelable operations from being processed. IfthrowOnFirstException
is false, this overload will aggregate any exceptions thrown into anAggregateException
, such that one callback throwing an exception will not prevent other registered callbacks from being executed.
The variable name is also wrong because Cancel is called on CancellationTokenSource
not the token itself and the source changes state of each token it manages.
You can create a Task with cancellation token, when you app goto background you can cancel this token.
You can do this in PCL https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle
var cancelToken = new CancellationTokenSource();
Task.Factory.StartNew(async () => {
await Task.Delay(10000);
// call web API
}, cancelToken.Token);
//this stops the Task:
cancelToken.Cancel(false);
Anther solution is user Timer in Xamarin.Forms, stop timer when app goto background https://xamarinhelp.com/xamarin-forms-timer/
You have to pass the CancellationToken
to the Task, which will periodically monitors the token to see whether cancellation is requested.
// CancellationTokenSource provides the token and have authority to cancel the token
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
// Task need to be cancelled with CancellationToken
Task task = Task.Run(async () => {
while(!token.IsCancellationRequested) {
Console.Write("*");
await Task.Delay(1000);
}
}, token);
Console.WriteLine("Press enter to stop the task");
Console.ReadLine();
cancellationTokenSource.Cancel();
In this case, the operation will end when cancellation is requested and the Task
will have a RanToCompletion
state. If you want to be acknowledged that your task has been cancelled, you have to use ThrowIfCancellationRequested
to throw an OperationCanceledException
exception.
Task task = Task.Run(async () =>
{
while (!token.IsCancellationRequested) {
Console.Write("*");
await Task.Delay(1000);
}
token.ThrowIfCancellationRequested();
}, token)
.ContinueWith(t =>
{
t.Exception?.Handle(e => true);
Console.WriteLine("You have canceled the task");
},TaskContinuationOptions.OnlyOnCanceled);
Console.WriteLine("Press enter to stop the task");
Console.ReadLine();
cancellationTokenSource.Cancel();
task.Wait();
Hope this helps to understand better.
You can use ThrowIfCancellationRequested
without handling the exception!
The use of ThrowIfCancellationRequested
is meant to be used from within a Task
(not a Thread
).
When used within a Task
, you do not have to handle the exception yourself (and get the Unhandled Exception error). It will result in leaving the Task
, and the Task.IsCancelled
property will be True. No exception handling needed.
In your specific case, change the Thread
to a Task
.
Task t = null;
try
{
t = Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}
if (t.IsCancelled)
{
Console.WriteLine("Canceled!");
}
You can implement your work method as follows:
private static void Work(CancellationToken cancelToken)
{
while (true)
{
if(cancelToken.IsCancellationRequested)
{
return;
}
Console.Write("345");
}
}
That's it. You always need to handle cancellation by yourself - exit from method when it is appropriate time to exit (so that your work and data is in consistent state)
UPDATE: I prefer not writing while (!cancelToken.IsCancellationRequested)
because often there are few exit points where you can stop executing safely across loop body, and loop usually have some logical condition to exit (iterate over all items in collection etc.). So I believe it's better not to mix that conditions as they have different intention.
Cautionary note about avoiding CancellationToken.ThrowIfCancellationRequested()
:
Comment in question by Eamon Nerbonne:
... replacing
ThrowIfCancellationRequested
with a bunch of checks forIsCancellationRequested
exits gracefully, as this answer says. But that's not just an implementation detail; that affects observable behavior: the task will no longer end in the cancelled state, but inRanToCompletion
. And that can affect not just explicit state checks, but also, more subtly, task chaining with e.g.ContinueWith
, depending on theTaskContinuationOptions
used. I'd say that avoidingThrowIfCancellationRequested
is dangerous advice.