예제 #1
0
        /// <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 (null == action)
            {
                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(si);
        }
예제 #2
0
        /// <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 (other is null)
            {
                return(1);
            }

            return(comparer.Compare(DueTime, other.DueTime));
        }
예제 #3
0
        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();
                }
            }
        }
예제 #4
0
 /// <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><c>true</c> if the item was found; <c>false</c> otherwise.</returns>
 public bool Remove(ScheduledItem <TAbsolute> scheduledItem) => queue.Remove(scheduledItem);
예제 #5
0
 /// <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);
예제 #6
0
        /// <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, ConcurrencyAbstraction.Current.StartTimer(Tick, next, due));
                        }
                    }

                    if (readyList.Count > 0)
                    {
                        ready = readyList.ToArray();
                        readyList.Clear();
                    }
                }

                if (null != ready)
                {
                    foreach (var item in ready)
                    {
                        if (!item.IsCanceled)
                        {
                            item.Invoke();
                        }
                    }
                }

                if (ExitIfEmpty)
                {
                    lock (gate)
                    {
                        if (readyList.Count == 0 && queue.Count == 0)
                        {
                            thread = null;
                            return;
                        }
                    }
                }
            }
        }
예제 #7
0
        /// <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 (null == action)
            {
                throw new ArgumentNullException(nameof(action));
            }

            SchedulerQueue <TimeSpan> queue;

            // There is no timed task and no task is currently running
            if (false == running)
            {
                running = true;

                if (TimeSpan.Zero < dueTime)
                {
                    ConcurrencyAbstraction.Current.Sleep(dueTime);
                }

                // execute directly without queueing
                IDisposable disposable;

                try
                {
                    disposable = action(this, state);
                }
                catch
                {
                    SetQueue(null);
                    running = false;
                    throw;
                }

                // did recursive tasks arrive?
                queue = GetQueue();

                // yes, run those in the queue as well
                if (null != queue)
                {
                    try
                    {
                        Trampoline.Run(queue);
                    }
                    finally
                    {
                        SetQueue(null);
                        running = false;
                    }
                }
                else
                {
                    running = false;
                }

                return(disposable);
            }

            queue = GetQueue();

            // if there is a task running or there is a queue
            if (null == queue)
            {
                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);
        }