Cancelling a Sleeping Task

Preparations for an executable (application or service) that will implement different Tasks. Some of the tasks will work continuously, while other will only perform their operations periodically with long intervals (hours) betwen the operations.

Of course, simple techniques such as Busy waiting must be avoided, and Sleep looping (why isn’t that a Wikipedia entry?) is not what I am looking for. And calling Thread.Sleep() with a long timeout value cannot be cancelled while the thread is sleeping.

The alternative I found was to use WaitHandle.Wait(), which waits for an event and also accepts a timeout as the maximum time to wait for the event.

My first approach was to create a ManualResetEvent that the task is Wait()ing for, and trigger that event when the cancellation is triggered:

static void SleepTaskMethod(int s, CancellationToken t)
{
  var mre = new ManualResetEvent(false);

  // cancellation fires MRE
  t.Register(() =>
  {
    Console.WriteLine("Cancellation " + s);
    mre.Set();
  }, true);

  while (!t.IsCancellationRequested)
  {
    Console.WriteLine("loop/sleep " + s);

    // wait for MRE (cancellation) or timeout
    Console.WriteLine("waitone " + s + " " + mre.WaitOne(5000));
  }

  Console.WriteLine("\nEnd " + s);
}

Then I found that a CancellationToken also exposes a WaitHandle, and rewrote the code as

static void SleepTaskMethod(int s, CancellationToken t)
{
  while (!t.IsCancellationRequested)
  {
    Console.WriteLine("loop/sleep " + s);

    Console.WriteLine("waitone " + s + " " + t.WaitHandle.WaitOne(5000));
  }

  Console.WriteLine("\nEnd " + s);
}

For both solutions, the task is invoked and cancelled using the same code:

var cts = new CancellationTokenSource();
var tasks = new List();
tasks.Add(new Task(() => { SleepTaskMethod(dummy, cts.Token); }));
foreach (var t in tasks)
  t.Start();

Console.WriteLine("press key to stop tasks");
Console.ReadKey();
Console.WriteLine("\nstopping task");

cts.Cancel();
Task.WaitAll(tasks.ToArray());

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: