0

I have a problem with cancellation token that doesn't work. I created a simple code example of my actual project. This is my scenario:

class Program
{
    static void Main(string[] args)
    {
        var taskCheker = new TaskChecker();
        taskCheker.Test();
        Console.ReadKey();
    }

}
public class TaskChecker
{
    public void Test()
    {
        var list = Enumerable.Range(0, 10);
        Parallel.ForEach(list, (item) =>
        {
            CancellationTokenSource cancellationToken = new CancellationTokenSource();
            cancellationToken.CancelAfter(1000);
            try
            {
                var task = Task.Run(() =>
                {
                    Console.WriteLine($"item: {item} with thread: {Thread.CurrentThread.ManagedThreadId} started");
                    LongTask();
                    Console.WriteLine($"item: {item} with thread: {Thread.CurrentThread.ManagedThreadId} finished");
                }, cancellationToken.Token);
                Task.WaitAll(new[] { task });
            }
            catch (TaskCanceledException)
            {
                Console.WriteLine("TaskCanceledException runned");
            }
            catch (Exception)
            {

                Console.WriteLine("Exception runned");
            }

        });
        Console.WriteLine("Parallel finished");
        Console.ReadKey();
    }

    public void LongTask()
    {
        Thread.Sleep(2000);
    }
}

I have a Parallel.Foreach that calls inner Task for each item. Inner Task has a cancellation token with 1 second. Inner Task call a LongTask method that it takes 2 seconds, and I expect that all of my inner tasks throw timeout. But all of them call and after 2 seconds will complete. So I don't know why my cancellation token doesn't work.

Thank you so much to your help

Amirhossein Yari
  • 2,054
  • 3
  • 26
  • 38
  • This article explains quite well what the `CancellationToken` does in this case: [A Tour of Task, Part 9: Delegate Tasks](https://blog.stephencleary.com/2015/03/a-tour-of-task-part-9-delegate-tasks.html) – Theodor Zoulias Aug 02 '21 at 12:13
  • The following question might be relevant to what you are trying to achieve: [How to abort a Task like aborting a Thread?](https://stackoverflow.com/questions/4359910/how-to-abort-a-task-like-aborting-a-thread-thread-abort-method) If you find it interesting, make sure to read also this: [What's wrong with using Thread.Abort()](https://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort) – Theodor Zoulias Aug 02 '21 at 12:39

1 Answers1

2

In Task.Run if the IsCancellationRequested is set to true before the task is actually running then it won't run.

But if the task already running before the IsCancellationRequested is true then it's your responsibility to call ThrowIfCancellationRequested in your task.

This is from MSDN:

Cancellation is cooperative and is not forced on the listener. The listener determines how to gracefully terminate in response to a cancellation request.

MSDN Source

HMZ
  • 2,949
  • 1
  • 19
  • 30
  • What I have to do for timeout, I don't want to call `IsCancellationRequested ` manualy – Amirhossein Yari Aug 02 '21 at 11:57
  • @AmirhosseinYari as he said, is impossible to do what you want (stop task without verify IsCancellationRequested in task code). This because cancellation token is a graceful attempt to terminate one task. Graceful not forced. If you want to stop a task (no matter what he does) you should use a `Kill()` – Giovanni Esposito Aug 02 '21 at 12:06
  • @AmirhosseinYari `Task.Wait` takes a `TimeSpan` your can set a timeout for each task. – HMZ Aug 02 '21 at 12:08
  • Task.Wait doesn't wok too!. Thank you @HMZ,@Giovanni Esposito, I didn't know about graceful behavior – Amirhossein Yari Aug 02 '21 at 12:16
  • But I couldn't find a way to do that yet. – Amirhossein Yari Aug 02 '21 at 12:17