Reputation: 1837
I need to call a method in action of my Task object. My task performs some kind of reading and I cancel the operation if it takes more than 2 seconds to complete.
I have this code as simulation:
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(2000));
var task = Task.Run(() =>
{
try
{
int i = 0;
while (true)
{
Thread.Sleep(500);
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("i = {0}", i);
i++;
if (i > 3) throw new InvalidOperationException();
}
}
catch (Exception e)
{
Console.WriteLine("Exception {0}", e.Message);
throw;
}
});
task.ContinueWith(t => Console.WriteLine(t.Status), TaskContinuationOptions.NotOnRanToCompletion);
My console outout is as follows:
This is what I expect and works for me. If I copy the code inside the task and create a method I no longer get the task status as Cancelled. I get status as Faulted. I must know if the operation was cancelled or an exception happened while reading process. I cannot figure out why I do not get the task status as Cancelled here.
var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(2000));
var task = Task.Run(() =>
{
try
{
Tester(cts);
}
catch (Exception e)
{
Console.WriteLine("Exception {0}", e.Message);
throw;
}
});
private static void Tester(CancellationTokenSource cts)
{
int i = 0;
while (true)
{
Thread.Sleep(500);
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("i = {0}", i);
i++;
if (i > 3) throw new InvalidOperationException();
}
}
Upvotes: 1
Views: 1308
Reputation: 10863
You get the expected Canceled
result, if you pass the token to Task.Run
:
var task = Task.Run(() =>
{
try
{
Tester(cts);
}
catch (Exception e)
{
Console.WriteLine("Exception {0}", e.Message);
throw;
}
}, cts.Token);
The task needs to know which token will throw the OperationCanceledException
- only an exception from the correct source cancels the task, every other exception will just fault it.
From MSDN:
When a task instance observes an OperationCanceledException thrown by user code, it compares the exception's token to its associated token (the one that was passed to the API that created the Task). If they are the same and the token's IsCancellationRequested property returns true, the task interprets this as acknowledging cancellation and transitions to the Canceled state.
I don't fully understand why you get the Canceled
result in the first place, it looks like it has to do with when the CancellationTokenSource
is captured.
Upvotes: 2