internal static void InvokeUnhandledTimerException(TimerExceptionEventArgs e) { UnhandledTimerException?.Invoke(e); }
/// <summary> /// Slices the timer thread and calls OnTick() method. /// </summary> internal static void Run() { var measureSlice = new Stopwatch(); var measureTimer = new Stopwatch(); while (!Service.IsStopping) { try { //Removed lock (fQueue) wrapping the entire block, seemed unnecessary since it's a concurrent queue. measureSlice.Start(); int index = 0; while (index < fBreakCount && fQueue.Count != 0) { Timer t; if (!fQueue.TryDequeue(out t)) { return; } try { measureTimer.Start(); t.OnTick(); measureTimer.Stop(); if (measureTimer.ElapsedMilliseconds > 50) { Service.Logger.Log( LogLevel.Warning, String.Format("Slow Timer: {0}, {1}ms.", t.ToString(), measureTimer.ElapsedMilliseconds) ); } measureTimer.Reset(); } catch (Exception ex) { TimerExceptionEventArgs args = new TimerExceptionEventArgs(t, ex); if (t.OnError != null) // There is a specific handler attached, execute that one { t.OnError(args); } if (!args.Handled) // Still not handled, try the global handler { Service.InvokeUnhandledTimerException(args); } if (args.StopTimer) { t.Stop(); } if (!args.Handled) { throw; } } t.fQueued = false; ++index; } // Calculate the time we have to sleep measureSlice.Stop(); var interval = 1000000 * 33; // 33 millisecond interval intended var sleepDuration = (int)Math.Max((interval - measureSlice.ElapsedTicks) / 1000000, 1); // Sleep the specified time, aiming for predictable flush interval Thread.Sleep(sleepDuration); measureSlice.Reset(); } catch (Exception ex) { // Log the exception, but do not stop the thread. Service.Logger.Log(ex); } } }