|
@@ -22,16 +22,21 @@ namespace System.Reactive.Concurrency
|
|
|
|
|
|
public IDisposable StartPeriodicTimer(Action action, TimeSpan period)
|
|
|
{
|
|
|
- //
|
|
|
- // MSDN documentation states the following:
|
|
|
- //
|
|
|
- // "If period is zero (0) or negative one (-1) milliseconds and dueTime is positive, callback is invoked once;
|
|
|
- // the periodic behavior of the timer is disabled, but can be re-enabled using the Change method."
|
|
|
- //
|
|
|
- if (period <= TimeSpan.Zero)
|
|
|
+ if (period < TimeSpan.Zero)
|
|
|
throw new ArgumentOutOfRangeException("period");
|
|
|
|
|
|
- return new PeriodicTimer(action, period);
|
|
|
+ //
|
|
|
+ // The contract for periodic scheduling in Rx is that specifying TimeSpan.Zero as the period causes the scheduler to
|
|
|
+ // call back periodically as fast as possible, sequentially.
|
|
|
+ //
|
|
|
+ if (period == TimeSpan.Zero)
|
|
|
+ {
|
|
|
+ return new FastPeriodicTimer(action);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return new PeriodicTimer(action, period);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public IDisposable QueueUserWorkItem(Action<object> action, object state)
|
|
@@ -362,6 +367,37 @@ namespace System.Reactive.Concurrency
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
+
|
|
|
+ class FastPeriodicTimer : IDisposable
|
|
|
+ {
|
|
|
+ private readonly Action _action;
|
|
|
+ private bool disposed;
|
|
|
+
|
|
|
+ public FastPeriodicTimer(Action action)
|
|
|
+ {
|
|
|
+ _action = action;
|
|
|
+
|
|
|
+ new System.Threading.Thread(Loop)
|
|
|
+ {
|
|
|
+ Name = "Rx-FastPeriodicTimer",
|
|
|
+ IsBackground = true
|
|
|
+ }
|
|
|
+ .Start();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Loop()
|
|
|
+ {
|
|
|
+ while (!disposed)
|
|
|
+ {
|
|
|
+ _action();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ disposed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
#else
|
|
@@ -389,28 +425,35 @@ namespace System.Reactive.Concurrency
|
|
|
|
|
|
public IDisposable StartPeriodicTimer(Action action, TimeSpan period)
|
|
|
{
|
|
|
- var cancel = new CancellationDisposable();
|
|
|
-
|
|
|
- var moveNext = default(Action);
|
|
|
- moveNext = () =>
|
|
|
+ if (period <= TimeSpan.Zero)
|
|
|
{
|
|
|
+ return new FastPeriodicTimer(action);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var cancel = new CancellationDisposable();
|
|
|
+
|
|
|
+ var moveNext = default(Action);
|
|
|
+ moveNext = () =>
|
|
|
+ {
|
|
|
#if USE_TASKEX
|
|
|
TaskEx.Delay(period, cancel.Token).ContinueWith(
|
|
|
#else
|
|
|
- Task.Delay(period, cancel.Token).ContinueWith(
|
|
|
+ Task.Delay(period, cancel.Token).ContinueWith(
|
|
|
#endif
|
|
|
- _ =>
|
|
|
- {
|
|
|
- moveNext();
|
|
|
- action();
|
|
|
- },
|
|
|
- TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
- moveNext();
|
|
|
-
|
|
|
- return cancel;
|
|
|
+ _ =>
|
|
|
+ {
|
|
|
+ moveNext();
|
|
|
+ action();
|
|
|
+ },
|
|
|
+ TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ moveNext();
|
|
|
+
|
|
|
+ return cancel;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public IDisposable QueueUserWorkItem(Action<object> action, object state)
|
|
@@ -447,6 +490,32 @@ namespace System.Reactive.Concurrency
|
|
|
action(state);
|
|
|
}, TaskCreationOptions.LongRunning);
|
|
|
}
|
|
|
+
|
|
|
+ class FastPeriodicTimer : IDisposable
|
|
|
+ {
|
|
|
+ private readonly Action _action;
|
|
|
+ private bool disposed;
|
|
|
+
|
|
|
+ public FastPeriodicTimer(Action action)
|
|
|
+ {
|
|
|
+ _action = action;
|
|
|
+
|
|
|
+ Task.Factory.StartNew(Loop, TaskCreationOptions.LongRunning);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Loop()
|
|
|
+ {
|
|
|
+ while (!disposed)
|
|
|
+ {
|
|
|
+ _action();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ disposed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
#endif
|