I have a task that is doing an infinite loop.
I have a CancellationToken that I pass both to the Task.Run call as to the actual ExecutePoll function.
I wait for a few seconds and Cancel the token.
There is one Continuation that should run when the task is cancelled.
Turns out this continuation only runs if I explicitly call cancellationToken.ThrowIfCancellationRequested();. If I only break out of the loop the task is always in the status: RanToCompletion
Can anyone share some light as to what I am getting wrong here?
CODE:
using System.Threading;
using System.Threading.Tasks;
namespace TaskCancellationTest
{
class Program
{
private static CancellationTokenSource _pollProcessTokenSource;
static async Task Main(string[] args)
{
InitPollingProcess();
await Task.Delay(5000);
Console.WriteLine("Cancelling loop");
_pollProcessTokenSource.Cancel();
Console.WriteLine("Loop cancelled");
Console.ReadLine();
}
private static void InitPollingProcess()
{
try
{
_pollProcessTokenSource = new CancellationTokenSource();
Task pollForListenerConfigs = Task.Run(async () =>
{
await ExecutePoll(_pollProcessTokenSource.Token);
},
_pollProcessTokenSource.Token);
pollForListenerConfigs.ContinueWith(_ =>
{
Console.WriteLine("Poll process stopped!");
}, TaskContinuationOptions.OnlyOnCanceled);
pollForListenerConfigs.ContinueWith(t =>
{
Console.WriteLine($"Task status: {t.Status}");
});
}
catch (Exception ex)
{
Console.WriteLine($"Poll process failed with Exception:\n {ex.Message}");
}
}
private static async Task ExecutePoll(CancellationToken cancellationToken)
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Exit from poll loop!");
//cancellationToken.ThrowIfCancellationRequested(); // UNCOMMENT TO MAKE CONTINUATION RUN
break;
}
Console.WriteLine("Looping...");
await Task.Delay(1000);
}
}
}
}
CodePudding user response:
There is nothing wrong, it is well explained here:
You can terminate the operation by using one of these options:
By simply returning from the delegate. In many scenarios this is sufficient; however, a task instance that is canceled in this way transitions to the TaskStatus.RanToCompletion state, not to the TaskStatus.Canceled state.
By throwing a OperationCanceledException and passing it the token on which cancellation was requested. The preferred way to do this is to use the ThrowIfCancellationRequested method. A task that is canceled in this way transitions to the Canceled state, which the calling code can use to verify that the task responded to its cancellation request.