public void Dispose()
 {
     this.head?.Dispose();
     this.tail?.Dispose();
     this.head = null;
     this.tail = null;
 }
            private HashedWheelTimeout PollTimeout()
            {
                HashedWheelTimeout head = this.head;

                if (head == null)
                {
                    return(null);
                }
                HashedWheelTimeout next = head.Next;

                if (next == null)
                {
                    tail = this.head = null;
                }
                else
                {
                    this.head = next;
                    next.Prev = null;
                }

                // null out prev and next to allow for GC.
                head.Next = null;
                head.Prev = null;
                return(head);
            }
            private void transferTimeoutsToBuckets()
            {
                // transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just
                // adds new timeouts in a loop.
                for (int i = 0; i < 100000; i++)
                {
                    HashedWheelTimeout timeout = null;
                    if (!_timer._timeouts.TryDequeue(out timeout))
                    {
                        // all processed
                        break;
                    }
                    if (timeout.State == HashedWheelTimeout.ST_CANCELLED ||
                        !timeout.CompareAndSetState(HashedWheelTimeout.ST_INIT, HashedWheelTimeout.ST_IN_BUCKET))
                    {
                        // Was cancelled in the meantime. So just remove it and continue with next HashedWheelTimeout
                        // in the queue
                        timeout.Remove();
                        continue;
                    }
                    long calculated      = timeout.Deadline / this._timer._tickDurationTicks;
                    long remainingRounds = (calculated - tick) / this._timer._wheel.Length;
                    timeout.RemainingRounds = remainingRounds;

                    long ticks     = Math.Max(calculated, tick); // Ensure we don't schedule for past.
                    int  stopIndex = (int)(ticks & this._timer._mask);

                    HashedWheelBucket bucket = _timer._wheel[stopIndex];
                    bucket.addTimeout(timeout);
                }
            }
 /**
  * 添加一个<see cref="HashedWheelTimeout"/> 到哈希桶中。
  */
 public void addTimeout(HashedWheelTimeout timeout)
 {
     //assert timeout.bucket == null;
     timeout.Bucket = this;
     if (head == null)
     {
         head = tail = timeout;
     }
     else
     {
         tail.Next    = timeout;
         timeout.Prev = tail;
         tail         = timeout;
     }
 }
Esempio n. 5
0
        public ITimeout NewTimeout(ITimerTask task, TimeSpan delay)
        {
            Guard.ArgumentNotNull(task, nameof(task));


            this.Start();
            var now = DateTime.UtcNow.Ticks;
            // 添加任务到下一个时间刻度。
            // 任务被处理后会被装进 HashedWheelBucket 桶。
            long deadline = now + (long)(delay.TotalMilliseconds * 10000L) - startTime;
            HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);

            _timeouts.Enqueue(timeout);
            return(timeout);
        }
 /**
  * Clear this bucket and return all not expired / cancelled {@link Timeout}s.
  */
 public void ClearTimeouts(ISet <ITimeout> set)
 {
     while (true)
     {
         HashedWheelTimeout timeout = PollTimeout();
         if (timeout == null)
         {
             return;
         }
         if (timeout.IsExpired || timeout.IsCancelled)
         {
             continue;
         }
         set.Add(timeout);
     }
 }
            public void Run()
            {
                // Initialize the startTime.
                _timer.startTime = System.DateTime.UtcNow.Ticks;
                if (_timer.startTime == 0)
                {
                    // We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized.
                    _timer.startTime = 1;
                }
                // Notify the other threads waiting for the initialization at start().
                _timer._startTimeInitialized.Set();

                _waitHandler.Reset();
                do
                {
                    long deadline = WaitForNextTick();
                    //运行被中断。
                    if (deadline > 0)
                    {
                        transferTimeoutsToBuckets();
                        HashedWheelBucket bucket =
                            _timer._wheel[(int)(tick & _timer._mask)];
                        bucket.ExpireTimeouts(deadline);
                        tick++;
                    }
                } while (Interlocked.Read(ref this._timer.workerState) == WORKER_STATE_STARTED);

                // Fill the unprocessedTimeouts so we can return them from stop() method.
                foreach (HashedWheelBucket bucket in _timer._wheel)
                {
                    bucket.ClearTimeouts(unprocessedTimeouts);
                }
                HashedWheelTimeout timeout = null;

                while (_timer._timeouts.TryDequeue(out timeout))
                {
                    unprocessedTimeouts.Add(timeout);
                }
            }
            /// <summary>
            /// 过期所有给定 <paramref name="deadline"/> 的 <see cref="HashedWheelTimeout"/>。
            /// </summary>
            /// <param name="deadline"></param>
            public void ExpireTimeouts(long deadline)
            {
                HashedWheelTimeout timeout = head;

                // process all timeouts
                while (timeout != null)
                {
                    bool remove = false;
                    if (timeout.RemainingRounds <= 0)
                    {
                        if (timeout.Deadline <= deadline)
                        {
                            timeout.Expire();
                        }
                        else
                        {
                            // The timeout was placed into a wrong slot. This should never happen.
                            throw new HashedWheelTimerException($"timeout.deadline ({timeout.Deadline}) > deadline ({deadline})");
                        }
                        remove = true;
                    }
                    else if (timeout.IsCancelled)
                    {
                        remove = true;
                    }
                    else
                    {
                        timeout.RemainingRounds--;
                    }
                    // store reference to next as we may null out timeout.next in the remove block.
                    HashedWheelTimeout next = timeout.Next;
                    if (remove)
                    {
                        this.Remove(timeout);
                    }
                    timeout = next;
                }
            }
            public void Remove(HashedWheelTimeout timeout)
            {
                HashedWheelTimeout next = timeout.Next;

                // remove timeout that was either processed or cancelled by updating the linked-list
                if (timeout.Prev != null)
                {
                    timeout.Prev.Next = next;
                }
                if (timeout.Next != null)
                {
                    timeout.Next.Prev = timeout.Prev;
                }

                if (timeout == head)
                {
                    // if timeout is also the tail we need to adjust the entry too
                    if (timeout == tail)
                    {
                        tail = null;
                        head = null;
                    }
                    else
                    {
                        head = next;
                    }
                }
                else if (timeout == tail)
                {
                    // if the timeout is the tail modify the tail to be the prev node.
                    tail = timeout.Prev;
                }
                // null out prev, next and bucket to allow for GC.
                timeout.Prev   = null;
                timeout.Next   = null;
                timeout.Bucket = null;
            }