Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to delay the start of a Task

I want to schedule a task to start in x ms and be able to cancel it before it starts (or just at the beginning of the task).

The first attempt would be something like

var _cancelationTokenSource = new CancellationTokenSource();  var token = _cancelationTokenSource.Token; Task.Factory.StartNew(() =>     {         token.ThrowIfCancellationRequested();         Thread.Sleep(100);         token.ThrowIfCancellationRequested();     }).ContinueWith(t =>     {         token.ThrowIfCancellationRequested();         DoWork();         token.ThrowIfCancellationRequested();     }, token); 

But I feel like there should be a better way, as this would use up a thread while in the sleep, during which it could be canceled.

What are my other options?

like image 744
Bruno Lopes Avatar asked Feb 14 '11 09:02

Bruno Lopes


People also ask

What does task delay mean?

Task Delay means non-meeting of the preplanned due date of a task.

What is Delay task for up to random delay?

Some of these tasks are randomly delayed tasks. Note To create a randomly delayed task in Task Scheduler, click to select the Delay task for up to (random delay) check box, and then specify a time period from the drop-down menu. You use a time-based trigger to run these tasks at some scheduled times.

Does task delay block thread?

Delay(1000) doesn't block the thread, unlike Task. Delay(1000).


2 Answers

Like Damien_The_Unbeliever mentioned, the Async CTP includes Task.Delay. Fortunately, we have Reflector:

public static class TaskEx {     static readonly Task _sPreCompletedTask = GetCompletedTask();     static readonly Task _sPreCanceledTask = GetPreCanceledTask();      public static Task Delay(int dueTimeMs, CancellationToken cancellationToken)     {         if (dueTimeMs < -1)             throw new ArgumentOutOfRangeException("dueTimeMs", "Invalid due time");         if (cancellationToken.IsCancellationRequested)             return _sPreCanceledTask;         if (dueTimeMs == 0)             return _sPreCompletedTask;          var tcs = new TaskCompletionSource<object>();         var ctr = new CancellationTokenRegistration();         var timer = new Timer(delegate(object self)         {             ctr.Dispose();             ((Timer)self).Dispose();             tcs.TrySetResult(null);         });         if (cancellationToken.CanBeCanceled)             ctr = cancellationToken.Register(delegate                                                  {                                                      timer.Dispose();                                                      tcs.TrySetCanceled();                                                  });          timer.Change(dueTimeMs, -1);         return tcs.Task;     }      private static Task GetPreCanceledTask()     {         var source = new TaskCompletionSource<object>();         source.TrySetCanceled();         return source.Task;     }      private static Task GetCompletedTask()     {         var source = new TaskCompletionSource<object>();         source.TrySetResult(null);         return source.Task;     } } 
like image 138
Ohad Schneider Avatar answered Sep 20 '22 17:09

Ohad Schneider


Since .NET 4.5 has now been released, there's a very simple built-in way to delay a task: just use Task.Delay(). behind the scenes, it uses the implementation that ohadsc decompiled.

like image 33
skolima Avatar answered Sep 20 '22 17:09

skolima