3

I read about the Cancellation methods but based on my understanding they all provide control over tasks from outside the task, but if i want to cancel a task from the inside.

For example in this pseudo code:

Task tasks = new Task(() =>
{ 
     bool exists = CheckFromDB();
      if (!exists)
         break;
}

Can i cancel a task from the inside? The only idea i got is to trigger an exception inside the task and handle it from outside but surly that is not the way to do.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
ykh
  • 1,775
  • 3
  • 31
  • 57

2 Answers2

11

If you want to truly Cancel the task (e.g. after it's completed the Status property would be set to Canceled), you can do it this way:

var cts = new CancellationTokenSource();
var token = cts.Token;

Task innerCancel = new Task(
    () =>
    {
        if (!CheckFromDB())
        {
            cts.Cancel();
        }
        token.ThrowIfCancellationRequested();
    },
    token);

When you use return task won't be actually canceled, but rather code after the return statement won't be executed, and the task itself will have its state as RanToCompletion.


On a side note it's advised to use Task.Factory.StartNew for .NET 4 and Task.Run for .NET 4.5 instead of constructor to create tasks.

Community
  • 1
  • 1
Yurii
  • 4,811
  • 7
  • 32
  • 41
  • This is a far better way to do it. – slugster Aug 16 '14 at 12:03
  • 1
    You should use `Task.Run` instead of `new Task` to return a hot task rather than a cold one – Yuval Itzchakov Aug 20 '14 at 07:46
  • @YuvalItzchakov, I agree with using `Task.Run` instead of returning a cold task, but in this case I've decided to follow up the way OP wrote it for the sake of consistency. – Yurii Aug 20 '14 at 07:54
  • I think you should show the OP the right path instead of sticking with an incorrect consistency :) – Yuval Itzchakov Aug 20 '14 at 07:59
  • Note if you have no need to cancel outside of the Task you can also drop the cancelation token and do `throw new OperationCanceledException()` in the place of `cts.Cancel()` to get a similar effect. – Scott Chamberlain Aug 21 '14 at 06:20
3

The lambda expression code inside a task behaves just the same as in any other method. If you want to end the task for some reason you can just simply return:

Task task = Task.Run(() =>
{ 
    if(!CheckFromDB())
    {
        return;
    }
}

You can also throw an exception. That will end the task and mark it as faulted but there's no reason to do so if you can avoid it. If you are really responding to some problem that you can't overcome, then yes, just throw an exception.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • Isn't there an property i can use or assign so that i can handle the return. – ykh Aug 16 '14 at 11:14
  • @user733659 To know that a specific return was made? not really... You can however make the lambda return a value (a boolean maybe). You could also throw a specific exception. – i3arnon Aug 16 '14 at 11:17
  • You can use events or a http://blogs.msdn.com/b/csharpfaq/archive/2010/07/19/parallel-programming-task-cancellation.aspx – hackp0int Aug 16 '14 at 11:18