History

GSF.Core: Added StaticTimer class to the solution.

StephenCWills committed 10 years ago

Commit 58e58201 parent b8314662 files · +174 −0Browse files

Showing the changes to Source/Libraries/GSF.Core/Threading/StaticTimer.cs (1 of 2 files). Show all

Unified · Split

Source/Libraries/GSF.Core/Threading/StaticTimer.cs+173−0
@@ -0,0 +1,173 @@
1//******************************************************************************************************
2// StaticTimer.cs - Gbtc
3//
4// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
5//
6// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
9// not use this file except in compliance with the License. You may obtain a copy of the License at:
10//
11// http://opensource.org/licenses/MIT
12//
13// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15// License for the specific language governing permissions and limitations.
16//
17// Code Modification History:
18// ----------------------------------------------------------------------------------------------------
19// 11/10/2016 - Stephen C. Wills
20// Generated original version of source code.
21//
22//******************************************************************************************************
23
24using System;
25using System.Collections.Concurrent;
26using System.Collections.Generic;
27
28namespace GSF.Threading
29{
30 /// <summary>
31 /// Represents a timer manager which registers callbacks
32 /// with existing timers to reduce thread pool queue burden.
33 /// </summary>
34 public class StaticTimer
35 {
36 #region [ Members ]
37
38 // Nested Types
39 private class TimerAction
40 {
41 private WeakAction m_action;
42 private CancellationToken m_cancellationToken;
43
44 public TimerAction(Action action, CancellationToken cancellationToken)
45 {
46 m_action = new WeakAction(action);
47 m_cancellationToken = cancellationToken;
48 }
49
50 public bool IsCancelled
51 {
52 get
53 {
54 return m_cancellationToken.IsCancelled;
55 }
56 }
57
58 public bool TryInvoke()
59 {
60 return m_action.TryInvoke();
61 }
62 }
63
64 // Fields
65 private readonly ConcurrentDictionary<int, ConcurrentQueue<TimerAction>> m_dataStreamMonitorActions;
66
67 #endregion
68
69 #region [ Constructors ]
70
71 /// <summary>
72 /// Creates a new instance of the <see cref="StaticTimer"/> class.
73 /// </summary>
74 public StaticTimer()
75 {
76 m_dataStreamMonitorActions = new ConcurrentDictionary<int, ConcurrentQueue<TimerAction>>();
77 }
78
79 #endregion
80
81 #region [ Methods ]
82
83 /// <summary>
84 /// Registers the given callback with the timer running at the given interval.
85 /// </summary>
86 /// <param name="interval">The interval at which to run the timer.</param>
87 /// <param name="monitorAction">The action to be performed when the timer is triggered.</param>
88 public ICancellationToken RegisterDataStreamMonitor(int interval, Action monitorAction)
89 {
90 CancellationToken cancellationToken = new CancellationToken();
91 RegisterDataStreamMonitor(interval, new TimerAction(monitorAction, cancellationToken));
92 return cancellationToken;
93 }
94
95 private void RegisterDataStreamMonitor(int interval, TimerAction monitorAction)
96 {
97 ConcurrentQueue<TimerAction> newQueue = null;
98 ConcurrentQueue<TimerAction> queue;
99
100 lock (m_dataStreamMonitorActions)
101 {
102 queue = m_dataStreamMonitorActions.GetOrAdd(interval, i => newQueue = new ConcurrentQueue<TimerAction>());
103 queue.Enqueue(monitorAction);
104 }
105
106 if (queue == newQueue)
107 StartTimer(interval, queue);
108 }
109
110 private void StartTimer(int interval, ConcurrentQueue<TimerAction> queue)
111 {
112 MonitorDataStream(interval, queue, new List<TimerAction>());
113 }
114
115 private void MonitorDataStream(int interval, ConcurrentQueue<TimerAction> queue, List<TimerAction> list)
116 {
117 TimerAction action;
118
119 for (int i = 0; i < list.Count; i++)
120 {
121 action = list[i];
122
123 // False here indicates that the
124 // action has been garbage collected
125 if (action.IsCancelled || !action.TryInvoke())
126 {
127 int end = list.Count - 1;
128 list[i] = list[end];
129 list.RemoveAt(end);
130 i--;
131 }
132 }
133
134 // The queue is only used to populate the
135 // list from outside the async loop
136 while (queue.TryDequeue(out action))
137 list.Add(action);
138
139 if (list.Count > 0)
140 {
141 // We still have callbacks in the list so continue the async loop
142 new Action(() => MonitorDataStream(interval, queue, list)).DelayAndExecute(interval);
143 }
144 else
145 {
146 lock (m_dataStreamMonitorActions)
147 {
148 // We are retiring this async loop so we need
149 // to remove its queue from the lookup table
150 m_dataStreamMonitorActions.TryRemove(interval, out queue);
151
152 // However, actions may have been queued up in the meantime
153 // so we need to re-register them with a new async loop
154 while (queue.TryDequeue(out action))
155 RegisterDataStreamMonitor(interval, action);
156 }
157 }
158 }
159
160 #endregion
161
162 #region [ Static ]
163
164 // Static Fields
165
166 /// <summary>
167 /// Default instance of the <see cref="StaticTimer"/> class.
168 /// </summary>
169 public static readonly StaticTimer Default = new StaticTimer();
170
171 #endregion
172 }
173}

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