Norgul Norgul - 1 month ago 12
C# Question

c# async task cancellation

I have some problems getting a grasp on tasks and cancellation tokens. I've made a program that looks like this:

static void Main(string[] args)
{

CancellationTokenSource token = new CancellationTokenSource();
Stopwatch stop = new Stopwatch();
stop.Start();

for (int i = 0; i < 5; i++)
{
//Thread.Sleep(1000);
Task.Factory.StartNew(() => myLongTask(token.Token, (i + 1) * 1000));
}
while (true)
{
Thread.SpinWait(1000);
if (stop.ElapsedMilliseconds > 3000)
{
token.Cancel();
}
}
}

public static void myLongTask(CancellationToken token, int time)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancelled");
return;
}
var sw = Stopwatch.StartNew();
Console.WriteLine($"Task {time / 1000} started");
while (sw.ElapsedMilliseconds < time)
Thread.SpinWait(1000);
Console.WriteLine($"Task {time / 1000} ended");

}


I am running 5 tasks simultaneously (although when I don't include
Thread.Sleep()
the
for
loop seems to run before tasks are even started?). None of the tasks get ever cancelled when I run the program. Also what is bugging me is...what task am I really cancelling when calling
token.Cancel()
? How can I choose which of the 5 tasks will I kill? I can define each task by it's variable, but I can't access its
CancellationRequested
property since it is triggered with
CancellationToken
. Would I need 5 different tokens then?

Answer

None of the tasks get ever cancelled when I run the program.

That's because you're only ever checking the cancellation token at the start of the task. Once it's got past that first token.IsCancellationRequested check, cancelling the token does nothing. If you move your check into your loop, like this:

while (sw.ElapsedMilliseconds < time)
{
    if (token.IsCancellationRequested)
    {
        Console.WriteLine("Cancelled");
        return;
    }
    Thread.SpinWait(1000);
}

... then you'll see the tasks react appropriately.

Also what is bugging me is...what task am I really cancelling when calling token.Cancel()?

You're not cancelling a task - you're cancelling the cancellation token. Any task that observes that cancellation token will be cancelled (or complete, or whatever action it takes) but there's no direct correlation between a task and a token.

When we talk about "cancelling a task" we really mean "cancelling a token which we believe the task is observing".

Comments