The right way to delay the start of a task

I want to schedule a task to run at x ms and cancel it before it starts (or only at the beginning of the task).

The first attempt will be similar to

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 that there should be a better way, as this will use a thread during sleep, during which it could be undone.

What are my other options?

+53
c # task-parallel-library
Feb 14 2018-11-11T00
source share
6 answers

As mentioned by Damien_The_Unbeliever , Async CTP includes Task.Delay . Fortunately, we have a 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; } } 
+28
Jan 30 '12 at 18:05
source share

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

+19
Sep 14
source share

The correct answer in the future is likely to be Task.Delay . However, it is only available through Async CTP (and in CTP, it is on TaskEx, not Task).

Unfortunately, since it is only in CTP, there are also few links to documentation for it.

+8
Feb 14 2018-11-11T00:
source share

Take a look at TaskFactoryExtensions_Delayed in "Parallel Programming with .NET 4 Samples" .

+4
Jun 09 2018-11-11T00:
source share

I have not tested this, but here is the first pass in the wrapper methods to create the initial โ€œDelayโ€ task or continue after the delay. If you find a problem, feel free to fix it.

  public static Task StartDelayTask(int delay, CancellationToken token) { var source = new TaskCompletionSource<Object>(); Timer timer = null; timer = new Timer(s => { source.TrySetResult(null); timer.Dispose(); }, null, delay, -1); token.Register(() => source.TrySetCanceled()); return source.Task; } public static Task ContinueAfterDelay (this Task task, int delay, Action<Task> continuation, CancellationToken token) { var source = new TaskCompletionSource<Object>(); Timer timer = null; var startTimer = new Action<Task>(t => { timer = new Timer(s => { source.TrySetResult(null); timer.Dispose(); },null,delay,-1); }); task.ContinueWith (startTimer, token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); token.Register(() => source.TrySetCanceled()); return source.Task.ContinueWith(continuation, token); } 
+4
Jun 09 2018-11-11T00:
source share

You can use the Token.WaitHandle.WaitOne (int32 milliseconds) overload method to indicate the number of milliseconds waiting for your task. But the key difference between Thread.Sleep (xxx) and Token.WaitHandle.WaitOne (xxx), which later blocks the thread until the specified time expires or the token is canceled.

Here is an example

 void Main() { var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var task = Task.Factory.StartNew(() => { // wait for 5 seconds or user hit Enter key cancel the task token.WaitHandle.WaitOne(5000); token.ThrowIfCancellationRequested(); Console.WriteLine("Task started its work"); }); Console.WriteLine("Press 'Enter' key to cancel your task"); Console.Read(); tokenSource.Cancel(); } 
+3
Apr 18 '13 at 20:50
source share



All Articles