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; } }
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; }