29

Is this a good design for a background thread that needs to be run using the Task API in .Net 4? My only concern is if we want to cancel that task how I would do it? I know I can just set ProgramEnding to true but I know there is a CancellationToken in the Task API.

This is just an example sample of code so that one thread will be adding to a collection and another thread will be removing from it. The Task is setup as LongRunning as this needs to be running continuously whilst the program is running

private void RemoveFromBlockingCollection()
{
    while (!ProgramEnding)
    {
       foreach (var x in DataInQueue.GetConsumingEnumerable())
       {
          Console.WriteLine("Task={0}, obj={1}, Thread={2}"
                          , Task.CurrentId, x + " Removed"
                          , Thread.CurrentThread.ManagedThreadId);
       }
    }
}

private void button1_Click(object sender, EventArgs e)
{
   DataInQueue = new BlockingCollection<string>();
   var t9 = Task.Factory.StartNew(RemoveFromBlockingCollection
                                 , TaskCreationOptions.LongRunning);

   for (int i = 0; i < 100; i++)
   {
     DataInQueue.Add(i.ToString());
     Console.WriteLine("Task={0}, obj={1}, Thread={2}", 
                       Task.CurrentId, i + " Added", 
                       Thread.CurrentThread.ManagedThreadId);
     Thread.Sleep(100);
   }
   ProgramEnding = true;
}

UPDATE: I have found that I can remove the ProgramEnding boolean and use DataInQueue.CompleteAdding which which bring the thread to an end.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Jon
  • 38,814
  • 81
  • 233
  • 382

1 Answers1

26

As you already mentioned, you can use the CancellationToken. Do it this way:

var cancellationTokenSource = new CancellationTokenSource();
Task.Factory.StartNew(RemoveFromBlockingCollection
                      , TaskCreationOptions.LongRunning
                      , cancellationTokenSource.Token);  

And later in your code, you can cancel the task with:

cancellationTokenSource.Cancel();

In your long running task you can ask the token, if cancellation was requested:

if (cancellationTokenSource.Token.IsCancellationRequested)
Fischermaen
  • 12,238
  • 2
  • 39
  • 56
  • Is the use of a boolean to keep the thread alive a best practice or is there an API call? I have found I can use the CompleteAdding method on a BlockingCollection but if I'm not using a BlockingCollection and doing something else would the boolean be accpetable? – Jon Oct 27 '11 at 11:42
  • Yes, it would work. Or you use the CancellationToken I mentioned above. – Fischermaen Oct 27 '11 at 11:46
  • I can use that to cancel the thread I was just asking your opinion to keep a thread running? – Jon Oct 27 '11 at 11:54
  • To cancel a thread means to stop it from running. You have to check `if (cancellationTokenSource.Token.IsCancellationRequested)` in your thread coding to determine, if the thread should continue or stop. That's all, isn't it? – Fischermaen Oct 27 '11 at 12:02
  • Yup I understand but once you start a thread and it finishes its processes within it, it ends. I am wondering how you keep a thread alive. I simply used a boolean but didnt think it was elegant – Jon Oct 27 '11 at 12:13
  • I guess I can do while(!cancellationTokenSource.Token.IsCancellationRequested) { //do something} – Jon Oct 27 '11 at 12:13
  • @Jon: sorry I didn't understand what you've meant. Yes, if you will have a thread that is running for an undefinite time, you will have to use a while-loop like this `while(!cancellationTokenSource.Token.IsCancellationRequested) { // do, what you have to do ... }` – Fischermaen Oct 27 '11 at 12:16
  • Just a tip. The StartNew doesnt accept a CancellationTokenSource only a CancellationToken – Jon Oct 27 '11 at 12:36
  • @Jon ... that's what I know. So I provided the `.Token` as parameter. ;-) – Fischermaen Oct 27 '11 at 13:00
  • 17
    I don't see the method signature for the StartNew method you're using in the TaskFactory documentation(http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory(v=vs.110).aspx). The only StartNew methods that take TaskCreationOptions and a CancellationToken also take a TaskScheduler. – Matt Becker Aug 13 '14 at 17:35
  • The general consensus on this thread: http://stackoverflow.com/questions/7343211/cancelling-a-task-is-throwing-an-exception is that the best way to exit out of the running task is to make a call to CancellationTokenSource.Token.ThrowIfCancellationRequested() – Sudhanshu Mishra Nov 17 '15 at 03:16