17

http://msdn.microsoft.com/en-us/library/dd988458.aspx

UPD:

so, let's discuss this article then: http://msdn.microsoft.com/en-us/library/dd997396.aspx

I've changed that code a little:

    static void Main()
    {

        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Factory.StartNew(() =>
        {

            // Were we already canceled?
            ct.ThrowIfCancellationRequested();

            bool moreToDo = true;
            Thread.Sleep(5000);
            while (moreToDo)
            {

                // Poll on this property if you have to do
                // other cleanup before throwing.
                if (ct.IsCancellationRequested)
                {
                    Console.WriteLine("exit");
                    // Clean up here, then...
                    ct.ThrowIfCancellationRequested();
                }

            }
        }, tokenSource2.Token); // this parameter useless

        Console.WriteLine("sleep");
        Thread.Sleep(2000);
        Console.WriteLine("cancel");

        tokenSource2.Cancel();

        // Just continue on this thread, or Wait/WaitAll with try-catch:
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            foreach (var v in e.InnerExceptions)
            {
                Console.WriteLine(e.Message + " " + v.Message);
            }
        }

        Console.ReadKey();
    }

UPD: Well, this changes only task.IsCanceled, which is imho useless, due to I still ought to implement all manually.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
zerkms
  • 249,484
  • 69
  • 436
  • 539
  • See [Task Cancellation](http://msdn.microsoft.com/en-us/library/dd997396.aspx). – John Saunders Sep 11 '10 at 04:17
  • 2
    I've seen it. "}, tokenSource2.Token)" - this argument changes nothing. Either we have or not this Token passed - we will get an exception, because `ct` is handled by closure. – zerkms Sep 11 '10 at 04:27
  • 2
    Too bad there was no actual answer to this question, I'm also wondering about the need for that argument... it does appear to be completely useless for now. – Marcel Popescu Sep 15 '11 at 21:30
  • 1
    You should probably mark @VirusX's post as the real answer, since, it is the real answer and points out that it's not actually useless, and why. – BrainSlugs83 Dec 12 '13 at 23:35

2 Answers2

49

Due to comments, I'm posting another answer.

Consider the following code:

var tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;

tokenSource.Cancel(); 

var task = Task.Factory.StartNew(() =>
{    
  // Were we already canceled?
  ct.ThrowIfCancellationRequested();
  // do some processing
});

Even if the call tokenSource.Cancel() is issued before the task was actually started, you'll still allocate a worker thread from thread pool, so you'll waste some system resources.

But when you specify token argument in Task.Factory.StartNew, the task will be cancelled immediately, without allocating a worker thread.

VirusX
  • 953
  • 1
  • 9
  • 20
  • 2
    This should probably be the accepted answer -- posted on your behalf above. One question -- is there a way to get the current task's cancellation token that was passed in? Sort of like the equivalent of Dispatcher.CurrentDispatcher? – BrainSlugs83 Dec 12 '13 at 23:39
  • 4
    This stumped for quite some time. Is there any MSDN documentation that confirms this? – Abhijeet Patel Jul 08 '14 at 06:49
3

Cancellation with Tasks is still cooperative. You wouldn't want a thread to be killed in the middle of some critical operation. You need to check for it.

CancellationTokens are better than simpler constructs like a ManualResetEvent for signalling shutdown of an operation because you can cascade or combine them, for example, you can have one for overall application shutdown and you can combine it with one for canceling a particular task. The task only has to look at the one CancellationToken but you can cancel it from either CancellationTokenSource.

Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
  • so, how can I get that token argument in the Work()? – zerkms Sep 11 '10 at 04:33
  • 1
    Well, you can pass it in using http://msdn.microsoft.com/en-us/library/dd780315.aspx but the REAL utility of the cancellation tokens comes into play when you start implementing your own `TaskFactory` and want to have cascading cancellation tokens and such like and then it's far more powerful than a simple `ManualResetEvent` or similar. – Ian Mercer Sep 11 '10 at 04:56
  • @zerkms: Also read [cancellation](http://msdn.microsoft.com/en-us/library/dd997364.aspx) on MSDN which gives more of a high-level view of the unified cancellation framework. Task cancellation is just how `Task` objects use cancellation. If you read the "big picture" cancellation article, then the benefits should become clearer. – Stephen Cleary Sep 11 '10 at 12:15
  • 3
    The question was not about the whole cancellation framework (which is absurdly complicated). The question was, why is the token being passed to StartNew(), given that the task does not receive it as an argument? – Marcel Popescu Sep 15 '11 at 21:31
  • 1
    The framework uses internally even though it doesn't pass it on. Why is that complicated? For example, in the exception handling code for tasks you can see it being used. It's also used internally in `TaskDebugView`. – Ian Mercer Sep 15 '11 at 23:19
  • What noticeable difference will I see outside of "TaskDebugView" if I don't pass it in versus do pass it in? 'Cause I see none right now... – BrainSlugs83 Dec 12 '13 at 23:30