/// <summary> /// Schedules an action to be executed at dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Absolute time at which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception> public override IDisposable ScheduleAbsolute <TState>(TState state, TAbsolute dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } ScheduledItem <TAbsolute, TState>?si = null; var run = new Func <IScheduler, TState, IDisposable>((scheduler, state1) => { lock (_queue) { _queue.Remove(si !); // NB: Assigned before function is invoked. } return(action(scheduler, state1)); }); si = new ScheduledItem <TAbsolute, TState>(this, state, run, dueTime, Comparer); lock (_queue) { _queue.Enqueue(si); } return(si); }
/// <summary> /// Schedules an action to be executed after dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Relative time after which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception> public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException("action"); } var dt = Time + Scheduler.Normalize(dueTime); var si = new ScheduledItem <TimeSpan, TState>(this, state, action, dt); var queue = GetQueue(); if (queue == null) { queue = new SchedulerQueue <TimeSpan>(4); queue.Enqueue(si); CurrentThreadScheduler.SetQueue(queue); try { Trampoline.Run(queue); } finally { CurrentThreadScheduler.SetQueue(null); } } else { queue.Enqueue(si); } return(Disposable.Create(si.Cancel)); }
/// <summary> /// Schedules an action to be executed at dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Absolute time at which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception> public override IDisposable ScheduleAbsolute <TState>(TState state, TAbsolute dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } var si = default(ScheduledItem <TAbsolute, TState>); var run = new Func <IScheduler, TState, IDisposable>((scheduler, state1) => { lock (queue) { queue.Remove(si); } return(action(scheduler, state1)); }); si = new ScheduledItem <TAbsolute, TState>(this, state, run, dueTime, Comparer); lock (queue) { queue.Enqueue(si); } return(si); }
/// <summary> /// Schedules an action to be executed after dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Relative time after which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception> /// <exception cref="ObjectDisposedException">The scheduler has been disposed and doesn't accept new work.</exception> public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } var due = _stopwatch.Elapsed + dueTime; var si = new ScheduledItem <TimeSpan, TState>(this, state, action, due); lock (_gate) { if (_disposed) { throw new ObjectDisposedException(""); } if (dueTime <= TimeSpan.Zero) { _readyList.Enqueue(si); _evt.Release(); } else { _queue.Enqueue(si); _evt.Release(); } EnsureThread(); } return(Disposable.Create(si.Cancel)); }
public int CompareTo(ScheduledItem <TAbsolute> other) { if (other == null) { throw new ArgumentNullException("other"); } return(comparer.Compare(DueTime, other.DueTime)); }
/// <summary> /// Compares the work item with another work item based on absolute time values. /// </summary> /// <param name="other">Work item to compare the current work item to.</param> /// <returns>Relative ordering between this and the specified work item.</returns> /// <remarks>The inequality operators are overloaded to provide results consistent with the <see cref="IComparable"/> implementation. Equality operators implement traditional reference equality semantics.</remarks> public int CompareTo(ScheduledItem <TAbsolute> other) { // MSDN: By definition, any object compares greater than null, and two null references compare equal to each other. if (ReferenceEquals(other, null)) { return(1); } return(_comparer.Compare(DueTime, other.DueTime)); }
private void Tick(object state) { lock (_gate) { if (!_disposed) { var item = (ScheduledItem <TimeSpan>)state; if (item == _nextItem) { _nextItem = null; } if (_queue.Remove(item)) { _readyList.Enqueue(item); } _evt.Release(); } } }
/// <summary> /// Schedules an action to be executed at dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Absolute time at which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception> public override IDisposable ScheduleAbsolute <TState>(TState state, DateTimeOffset dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException("action"); } var si = default(ScheduledItem <DateTimeOffset, TState>); var run = new Func <IScheduler, TState, IDisposable>((scheduler, state1) => { queue.Remove(si); return(action(scheduler, state1)); }); si = new ScheduledItem <DateTimeOffset, TState>(this, state, run, dueTime, Comparer); queue.Enqueue(si); return(Disposable.Create(si.Cancel)); }
void AddTask(IList <ScheduledItem <TAbsolute> > tasks, ScheduledItem <TAbsolute> task) { // It is most likely appended in order, so don't use ineffective List.Sort(). Simple comparison makes it faster. // Also, it is important that events are processed *in order* when they are scheduled at the same moment. int pos = -1; TAbsolute dueTime = task.DueTime; for (int i = tasks.Count - 1; i >= 0; i--) { if (Comparer.Compare(dueTime, tasks [i].DueTime) >= 0) { tasks.Insert(i + 1, task); pos = i; break; } } if (pos < 0) { tasks.Insert(0, task); } }
/// <summary> /// Removes the specified work item from the scheduler queue. /// </summary> /// <param name="scheduledItem">Work item to be removed from the scheduler queue.</param> /// <returns>true if the item was found; false otherwise.</returns> public bool Remove(ScheduledItem <TAbsolute> scheduledItem) { return(_queue.Remove(scheduledItem)); }
/// <summary> /// Enqueues the specified work item to be scheduled. /// </summary> /// <param name="scheduledItem">Work item to be scheduled.</param> public void Enqueue(ScheduledItem <TAbsolute> scheduledItem) { _queue.Enqueue(scheduledItem); }
/// <summary> /// Event loop scheduled on the designated event loop thread. The loop is suspended/resumed using the event /// which gets set by calls to Schedule, the next item timer, or calls to Dispose. /// </summary> private void Run() { while (true) { _evt.Wait(); var ready = default(ScheduledItem <TimeSpan>[]); lock (_gate) { // // Bug fix that ensures the number of calls to Release never greatly exceeds the number of calls to Wait. // See work item #37: https://rx.codeplex.com/workitem/37 // while (_evt.CurrentCount > 0) { _evt.Wait(); } // // The event could have been set by a call to Dispose. This takes priority over anything else. We quit the // loop immediately. Subsequent calls to Schedule won't ever create a new thread. // if (_disposed) { _evt.Dispose(); return; } while (_queue.Count > 0 && _queue.Peek().DueTime <= _stopwatch.Elapsed) { var item = _queue.Dequeue(); _readyList.Enqueue(item); } if (_queue.Count > 0) { var next = _queue.Peek(); if (next != _nextItem) { _nextItem = next; var due = next.DueTime - _stopwatch.Elapsed; Disposable.TrySetSerial(ref _nextTimer, ConcurrencyAbstractionLayer.Current.StartTimer(Tick, next, due)); } } if (_readyList.Count > 0) { ready = _readyList.ToArray(); _readyList.Clear(); } } if (ready != null) { foreach (var item in ready) { if (!item.IsCanceled) { try { item.Invoke(); } catch (ObjectDisposedException ex) when(nameof(EventLoopScheduler).Equals(ex.ObjectName)) { // Since we are not inside the lock at this point // the scheduler can be disposed before the item had a chance to run } } } } if (ExitIfEmpty) { lock (_gate) { if (_readyList.Count == 0 && _queue.Count == 0) { _thread = null; return; } } } } }
public bool Remove(ScheduledItem <TAbsolute> scheduledItem) { throw new NotImplementedException(); }
/// <summary> /// Schedules an action to be executed after dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Relative time after which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception> public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } var queue = default(SchedulerQueue <TimeSpan>); // There is no timed task and no task is currently running if (!running) { running = true; if (dueTime > TimeSpan.Zero) { ConcurrencyAbstractionLayer.Current.Sleep(dueTime); } // execute directly without queueing IDisposable d; try { d = action(this, state); } catch { SetQueue(null); running = false; throw; } // did recursive tasks arrive? queue = GetQueue(); // yes, run those in the queue as well if (queue != null) { try { Trampoline.Run(queue); } finally { SetQueue(null); running = false; } } else { running = false; } return(d); } queue = GetQueue(); // if there is a task running or there is a queue if (queue == null) { queue = new SchedulerQueue <TimeSpan>(4); SetQueue(queue); } var dt = Time + Scheduler.Normalize(dueTime); // queue up more work var si = new ScheduledItem <TimeSpan, TState>(this, state, action, dt); queue.Enqueue(si); return(si); }
/// <summary> /// Event loop scheduled on the designated event loop thread. The loop is suspended/resumed using the event /// which gets set by calls to Schedule, the next item timer, or calls to Dispose. /// </summary> private void Run() { while (true) { #if !NO_CDS _evt.Wait(); #else _evt.WaitOne(); #endif var ready = default(ScheduledItem <SafeTimeSpan>[]); lock (_gate) { // // The event could have been set by a call to Dispose. This takes priority over anything else. We quit the // loop immediately. Subsequent calls to Schedule won't ever create a new thread. // if (_disposed) { ((IDisposable)_evt).Dispose(); return; } while (_queue.Count > 0 && (TimeSpan)_queue.Peek().DueTime <= _stopwatch.Elapsed) { var item = _queue.Dequeue(); _readyList.Enqueue(item); } if (_queue.Count > 0) { var next = _queue.Peek(); if (next != _nextItem) { _nextItem = next; var due = (TimeSpan)next.DueTime - _stopwatch.Elapsed; _nextTimer.Disposable = ConcurrencyAbstractionLayer.Current.StartTimer(Tick, next, due); } } if (_readyList.Count > 0) { ready = _readyList.ToArray(); _readyList.Clear(); } } if (ready != null) { foreach (var item in ready) { if (!item.IsCanceled) { item.Invoke(); } } } if (ExitIfEmpty) { lock (_gate) { if (_readyList.Count == 0 && _queue.Count == 0) { _thread = null; return; } } } } }
/// <summary> /// Event loop scheduled on the designated event loop thread. The loop is suspended/resumed using the event /// which gets set by calls to Schedule, the next item timer, or calls to Dispose. /// </summary> private void Run() { while (true) { _evt.Wait(); var ready = default(ScheduledItem <TimeSpan>[]); lock (_gate) { // // Bug fix that ensures the number of calls to Release never greatly exceeds the number of calls to Wait. // See work item #37: https://rx.codeplex.com/workitem/37 // while (_evt.CurrentCount > 0) { _evt.Wait(); } // // The event could have been set by a call to Dispose. This takes priority over anything else. We quit the // loop immediately. Subsequent calls to Schedule won't ever create a new thread. // if (_disposed) { ((IDisposable)_evt).Dispose(); return; } while (_queue.Count > 0 && _queue.Peek().DueTime <= _stopwatch.Elapsed) { var item = _queue.Dequeue(); _readyList.Enqueue(item); } if (_queue.Count > 0) { var next = _queue.Peek(); if (next != _nextItem) { _nextItem = next; var due = next.DueTime - _stopwatch.Elapsed; _nextTimer.Disposable = ConcurrencyAbstractionLayer.Current.StartTimer(Tick, next, due); } } if (_readyList.Count > 0) { ready = _readyList.ToArray(); _readyList.Clear(); } } if (ready != null) { foreach (var item in ready) { if (!item.IsCanceled) { item.Invoke(); } } } if (ExitIfEmpty) { lock (_gate) { if (_readyList.Count == 0 && _queue.Count == 0) { _thread = null; return; } } } } }
public void Enqueue(ScheduledItem <TAbsolute> scheduledItem) { throw new NotImplementedException(); }