I have threaded task wich performs some operation in loop:
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
ct.ThrowIfCancellationRequested();
}
}
static void DoSomeSeriousJob()
{
Console.WriteLine("Serious job started");
Thread.Sleep(5000);
Console.WriteLine("Serious job done");
}
I start it and then cancel after some period of time:
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => TaskAction(cts.Token), cts.Token);
Thread.Sleep(1000);
cts.Cancel();
This operation must be finished correctly, I don't want to interrupt it. But I want to send a cancellation request to my task and wait until it finishes correctly (by which I mean it gets to some point in code). I tryed following approaches:
try
{
task.Wait(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
// Must be joined here.
In this case program returns immediately from Wait()
. The task continues to run until ThrowIfCancellationRequested()
but if main thread exits the task gets interrupted too.
try
{
task.Wait();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Here main thread waits for completion but at the end AggregateException
is risen with InnerException
= TaskCancelledException
(not OperationCancelledException
).
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
if (ct.IsCancellationRequested)
break;
}
}
// ...
task.Wait();
In this case no exceptions are risen but the task gets status RanToCompletion
in the end. This is not distiguishable from correct completion when SomeCodition()
starts to return false.
All these problem have easy workarounds but I wonder, may be I'm missing something? Could anybody advise me better solution?
Wait is a synchronization method that causes the calling thread to wait until the current task has completed. If the current task has not started execution, the Wait method attempts to remove the task from the scheduler and execute it inline on the current thread.
You can cancel an asynchronous operation after a period of time by using the CancellationTokenSource. CancelAfter method if you don't want to wait for the operation to finish.
TaskCanceledException(String, Exception, CancellationToken) Initializes a new instance of the TaskCanceledException class with a specified error message, a reference to the inner exception that is the cause of this exception, and the CancellationToken that triggered the cancellation. TaskCanceledException(Task)
Create and start a cancelable task. Pass a cancellation token to your user delegate and optionally to the task instance. Notice and respond to the cancellation request in your user delegate. Optionally notice on the calling thread that the task was canceled.
If you want to wait for the task to complete (or gets cancelled) synchronously, you can try this:
cts.Cancel();
Task.Run(async () => {
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
).Wait();
So that you can directly catch OperationCanceledException instead of catching an AggregateException.
Edit:
Wait(CanecllationToken)
This approach won't work for that purpose. MSDN statement:
Waits for the Task to complete execution. The wait terminates if a cancellation token is canceled before the task completes.
Wait()
You can use this approach but as you can see, you should expect an AggregateException not OperationCanceledException. It is also specified in documents of the method.
The AggregateException.InnerExceptions collection contains a TaskCanceledException object.
So in this approach, in order to make sure operation is cancelled, you can check if inner expection contains a TaskCanceledException or not.
Check IsCancellationRequested() and no exceptions
In this way, this is obvious that no exception is thrown and you can't find out if the operation is cancelled or not.
If you don't want to wait synchronously, everything works as expected:
cts.Cancel();
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With