173 lines · 6.0 KB · C#
RawDownload
//******************************************************************************************************//  StaticTimer.cs - Gbtc////  Copyright © 2016, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  11/10/2016 - Stephen C. Wills//       Generated original version of source code.////****************************************************************************************************** using System;using System.Collections.Concurrent;using System.Collections.Generic; namespace GSF.Threading{    /// <summary>    /// Represents a timer manager which registers callbacks    /// with existing timers to reduce thread pool queue burden.    /// </summary>    public class StaticTimer    {        #region [ Members ]         // Nested Types        private class TimerAction        {            private WeakAction m_action;            private CancellationToken m_cancellationToken;             public TimerAction(Action action, CancellationToken cancellationToken)            {                m_action = new WeakAction(action);                m_cancellationToken = cancellationToken;            }             public bool IsCancelled            {                get                {                    return m_cancellationToken.IsCancelled;                }            }             public bool TryInvoke()            {                return m_action.TryInvoke();            }        }         // Fields        private readonly ConcurrentDictionary<int, ConcurrentQueue<TimerAction>> m_dataStreamMonitorActions;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new instance of the <see cref="StaticTimer"/> class.        /// </summary>        public StaticTimer()        {            m_dataStreamMonitorActions = new ConcurrentDictionary<int, ConcurrentQueue<TimerAction>>();        }         #endregion         #region [ Methods ]         /// <summary>        /// Registers the given callback with the timer running at the given interval.        /// </summary>        /// <param name="interval">The interval at which to run the timer.</param>        /// <param name="monitorAction">The action to be performed when the timer is triggered.</param>        public ICancellationToken RegisterDataStreamMonitor(int interval, Action monitorAction)        {            CancellationToken cancellationToken = new CancellationToken();            RegisterDataStreamMonitor(interval, new TimerAction(monitorAction, cancellationToken));            return cancellationToken;        }         private void RegisterDataStreamMonitor(int interval, TimerAction monitorAction)        {            ConcurrentQueue<TimerAction> newQueue = null;            ConcurrentQueue<TimerAction> queue;             lock (m_dataStreamMonitorActions)            {                queue = m_dataStreamMonitorActions.GetOrAdd(interval, i => newQueue = new ConcurrentQueue<TimerAction>());                queue.Enqueue(monitorAction);            }             if (queue == newQueue)                StartTimer(interval, queue);        }         private void StartTimer(int interval, ConcurrentQueue<TimerAction> queue)        {            MonitorDataStream(interval, queue, new List<TimerAction>());        }         private void MonitorDataStream(int interval, ConcurrentQueue<TimerAction> queue, List<TimerAction> list)        {            TimerAction action;             for (int i = 0; i < list.Count; i++)            {                action = list[i];                 // False here indicates that the                // action has been garbage collected                if (action.IsCancelled || !action.TryInvoke())                {                    int end = list.Count - 1;                    list[i] = list[end];                    list.RemoveAt(end);                    i--;                }            }             // The queue is only used to populate the            // list from outside the async loop            while (queue.TryDequeue(out action))                list.Add(action);             if (list.Count > 0)            {                // We still have callbacks in the list so continue the async loop                new Action(() => MonitorDataStream(interval, queue, list)).DelayAndExecute(interval);            }            else            {                lock (m_dataStreamMonitorActions)                {                    // We are retiring this async loop so we need                    // to remove its queue from the lookup table                    m_dataStreamMonitorActions.TryRemove(interval, out queue);                     // However, actions may have been queued up in the meantime                    // so we need to re-register them with a new async loop                    while (queue.TryDequeue(out action))                        RegisterDataStreamMonitor(interval, action);                }            }        }         #endregion         #region [ Static ]         // Static Fields         /// <summary>        /// Default instance of the <see cref="StaticTimer"/> class.        /// </summary>        public static readonly StaticTimer Default = new StaticTimer();         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t