History

Renamed folders and separated GSF.Media and GSF.Net into separate projects.

StephenCWills committed 14 years ago

Commit ac1ef661 parent 45bce55628 files · +733 −461Browse files

Showing the changes to Source/Libraries/GSF.Core/ReusableObjectPool.cs (1 of 628 files). Show all

Unified · Split

Source/Libraries/GSF.Core/ReusableObjectPool.cs+505−0
@@ -0,0 +1,505 @@
1+//******************************************************************************************************
2+// ReusableObjectPool.cs - Gbtc
3+//
4+// Copyright © 2010, 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 Eclipse Public License -v 1.0 (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://www.opensource.org/licenses/eclipse-1.0.php
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/23/2011 - J. Ritchie Carroll
20+// Generated original version of source code.
21+// 10/8/2012 - Danyelle Gilliam
22+// Modified Header
23+//
24+//******************************************************************************************************
25+
26+
27+
28+
29+#region [ Contributor License Agreements ]
30+
31+//******************************************************************************************************
32+//
33+// Copyright © 2011, Grid Protection Alliance. All Rights Reserved.
34+//
35+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
36+// not use this file except in compliance with the License. You may obtain a copy of the License at:
37+//
38+// http://www.opensource.org/licenses/eclipse-1.0.php
39+//
40+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
41+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
42+// License for the specific language governing permissions and limitations.
43+//
44+//******************************************************************************************************
45+
46+#endregion
47+
48+using System;
49+using System.Collections.Concurrent;
50+
51+namespace GSF
52+{
53+ /// <summary>
54+ /// Represents a reusable object pool that can be used by an application.
55+ /// </summary>
56+ /// <remarks>
57+ /// <para>
58+ /// Object pooling can offer a significant performance boost in some scenarios. It is most effective when the cost
59+ /// of construction is high and/or the rate of instantiation is high.
60+ /// </para>
61+ /// <para>
62+ /// This object pool is statically created at application startup, one per type, and is available for all components
63+ /// and classes within an application domain. Every time you need to use an object, you take one from the pool, use
64+ /// it, then return it to the pool when done. This process can be much faster than creating a new object every time
65+ /// you need to use one.
66+ /// </para>
67+ /// <para>
68+ /// When objects implement <see cref="ISupportLifecycle"/>, the <see cref="ReusableObjectPool{T}"/> will automatically
69+ /// attach to the <see cref="ISupportLifecycle.Disposed"/> event and return the object to the pool when it's disposed.
70+ /// When an object is taken from the pool, the <see cref="ISupportLifecycle.Initialize"/> method will be called to
71+ /// reinstantiate any need member variables. If class tracks a disposed flag, it should be reset during call to the
72+ /// <see cref="ISupportLifecycle.Initialize"/> method so that class will be "un-disposed". Also, typical dispose
73+ /// implementations call <see cref="GC.SuppressFinalize"/> in the <see cref="IDisposable.Dispose"/> method, as such the
74+ /// <see cref="GC.ReRegisterForFinalize"/> should be called during <see cref="ISupportLifecycle.Initialize"/> method to
75+ /// make sure class will be disposed by finalizer in case <see cref="IDisposable.Dispose"/> method is never called.
76+ /// <example>
77+ /// Here is an example class that implements <see cref="ISupportLifecycle"/> such that it will be automatically returned
78+ /// to the pool when the class is disposed and automatically initialized when taken from the pool:
79+ /// <code>
80+ /// /// &lt;summary&gt;
81+ /// /// Class that shows example implementation of reusable &lt;see cref="ISupportLifecycle"/&gt;.
82+ /// /// &lt;/summary&gt;
83+ /// public class ReusableClass : ISupportLifecycle
84+ /// {
85+ /// #region [ Members ]
86+ ///
87+ /// // Events
88+ ///
89+ /// /// &lt;summary&gt;
90+ /// /// Occurs when the &lt;see cref="ReusableClass"/&gt; is disposed.
91+ /// /// &lt;/summary&gt;
92+ /// public event EventHandler Disposed;
93+ ///
94+ /// // Fields
95+ /// private System.Timers.Timer m_timer; // Example member variable that needs initialization and disposal
96+ /// private bool m_enabled;
97+ /// private bool m_disposed;
98+ ///
99+ /// #endregion
100+ ///
101+ /// #region [ Constructors ]
102+ ///
103+ /// /// &lt;summary&gt;
104+ /// /// Releases the unmanaged resources before the &lt;see cref="ReusableClass"/&gt; object is reclaimed by &lt;see cref="GC"/&gt;.
105+ /// /// &lt;/summary&gt;
106+ /// ~ReusableClass()
107+ /// {
108+ /// Dispose(false);
109+ /// }
110+ ///
111+ /// #endregion
112+ ///
113+ /// #region [ Properties ]
114+ ///
115+ /// /// &lt;summary&gt;
116+ /// /// Gets or sets a boolean value that indicates whether the &lt;see cref="ReusableClass"/&gt; object is currently enabled.
117+ /// /// &lt;/summary&gt;
118+ /// public bool Enabled
119+ /// {
120+ /// get
121+ /// {
122+ /// return m_enabled;
123+ /// }
124+ /// set
125+ /// {
126+ /// m_enabled = value;
127+ ///
128+ /// if (m_timer != null)
129+ /// m_timer.Enabled = m_enabled;
130+ /// }
131+ /// }
132+ ///
133+ /// #endregion
134+ ///
135+ /// #region [ Methods ]
136+ ///
137+ /// /// &lt;summary&gt;
138+ /// /// Initializes the &lt;see cref="ReusableClass"/&gt; object.
139+ /// /// &lt;/summary&gt;
140+ /// public void Initialize()
141+ /// {
142+ /// // Undispose class instance if it is being reused
143+ /// if (m_disposed)
144+ /// {
145+ /// m_disposed = false;
146+ /// GC.ReRegisterForFinalize(this);
147+ /// }
148+ ///
149+ /// m_enabled = true;
150+ ///
151+ /// // Initialize member variables
152+ /// if (m_timer == null)
153+ /// {
154+ /// m_timer = new System.Timers.Timer(2000.0D);
155+ /// m_timer.Elapsed += m_timer_Elapsed;
156+ /// m_timer.Enabled = m_enabled;
157+ /// }
158+ /// }
159+ ///
160+ /// /// &lt;summary&gt;
161+ /// /// Releases all the resources used by the &lt;see cref="ReusableClass"/&gt; object.
162+ /// /// &lt;/summary&gt;
163+ /// public void Dispose()
164+ /// {
165+ /// Dispose(true);
166+ /// GC.SuppressFinalize(this);
167+ /// }
168+ ///
169+ /// /// &lt;summary&gt;
170+ /// /// Releases the unmanaged resources used by the &lt;see cref="ReusableClass"/&gt; object and optionally releases the managed resources.
171+ /// /// &lt;/summary&gt;
172+ /// /// &lt;param name="disposing"&gt;true to release both managed and unmanaged resources; false to release only unmanaged resources.&lt;/param&gt;
173+ /// protected virtual void Dispose(bool disposing)
174+ /// {
175+ /// if (!m_disposed)
176+ /// {
177+ /// try
178+ /// {
179+ /// if (disposing)
180+ /// {
181+ /// // Dispose member variables
182+ /// if (m_timer != null)
183+ /// {
184+ /// m_timer.Elapsed -= m_timer_Elapsed;
185+ /// m_timer.Dispose();
186+ /// }
187+ /// m_timer = null;
188+ ///
189+ /// m_enabled = false;
190+ /// }
191+ /// }
192+ /// finally
193+ /// {
194+ /// m_disposed = true;
195+ ///
196+ /// if (Disposed != null)
197+ /// Disposed(this, EventArgs.Empty);
198+ /// }
199+ /// }
200+ /// }
201+ ///
202+ /// // Handle timer event
203+ /// private void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
204+ /// {
205+ /// // Do work here...
206+ /// }
207+ ///
208+ /// #endregion
209+ /// }
210+ /// </code>
211+ /// </example>
212+ /// </para>
213+ /// <para>
214+ /// If the pool objects do not implement <see cref="ISupportLifecycle"/> you can still use the object pool, but it
215+ /// will be very imporant to return the object to the pool when you are finished using it. If you are using an object
216+ /// scoped within a method, make sure to use a try/finally so that you can take the object within the try and return
217+ /// the object within the finally. If you are using an object as a member scoped class field, make sure you use the
218+ /// standard dispose pattern and return the object during the <see cref="IDisposable.Dispose"/> method call. In this
219+ /// mode you will also need to manually initialze your object after you get it from the pool to reset its state.
220+ /// </para>
221+ /// </remarks>
222+ /// <typeparam name="T">Type of object to pool.</typeparam>
223+ public class ReusableObjectPool<T> where T : class, new()
224+ {
225+ private ConcurrentQueue<T> m_objectPool = new ConcurrentQueue<T>();
226+
227+ /// <summary>
228+ /// Gets an object from the pool, or creates a new one if no pool items are available.
229+ /// </summary>
230+ /// <returns>An available object from the pool, or a new one if no pool items are available.</returns>
231+ /// <remarks>
232+ /// If type of <typeparamref name="T"/> implements <see cref="ISupportLifecycle"/>, the pool will attach
233+ /// to the item's <see cref="ISupportLifecycle.Disposed"/> event such that the object can be automatically
234+ /// restored to the pool upon <see cref="IDisposable.Dispose"/>. It will be up to class implementors to
235+ /// make sure <see cref="ISupportLifecycle.Initialize"/> makes the class ready for use as this method will
236+ /// always be called for an object being taken from the pool.
237+ /// </remarks>
238+ public T TakeObject()
239+ {
240+ T item;
241+ bool newItem = false;
242+
243+ // Attempt to provide user with a queued item
244+ if (!m_objectPool.TryDequeue(out item))
245+ {
246+ // No items are available, create a new item for the object pool
247+ item = FastObjectFactory<T>.CreateObjectFunction();
248+ newItem = true;
249+ }
250+
251+ // Automatically handle class life cycle if item implements support for this
252+ ISupportLifecycle lifecycleItem = item as ISupportLifecycle;
253+
254+ if (lifecycleItem != null)
255+ {
256+ // Attach to dispose event so item can be automatically returned to the pool
257+ if (newItem)
258+ lifecycleItem.Disposed += LifecycleItem_Disposed;
259+
260+ // Initialize or reinitialize (i.e., un-dispose) the item
261+ lifecycleItem.Initialize();
262+ }
263+
264+ return item;
265+ }
266+
267+ /// <summary>
268+ /// Returns object to the pool.
269+ /// </summary>
270+ /// <param name="item">Reference to the object being returned.</param>
271+ /// <remarks>
272+ /// If type of <typeparamref name="T"/> implements <see cref="ISupportLifecycle"/>, the pool will automatically
273+ /// return the item to the pool when the <see cref="ISupportLifecycle.Disposed"/> event is raised, usually when
274+ /// the object's <see cref="IDisposable.Dispose"/> method is called.
275+ /// </remarks>
276+ public void ReturnObject(T item)
277+ {
278+ if (item != null)
279+ m_objectPool.Enqueue(item);
280+ }
281+
282+ /// <summary>
283+ /// Releases all the objects currently cached in the pool.
284+ /// </summary>
285+ public void Clear()
286+ {
287+ T item;
288+
289+ while (!m_objectPool.IsEmpty)
290+ {
291+ m_objectPool.TryDequeue(out item);
292+ }
293+ }
294+
295+ /// <summary>
296+ /// Allocates the pool to the desired <paramref name="size"/>.
297+ /// </summary>
298+ /// <param name="size">Desired pool size.</param>
299+ /// <exception cref="ArgumentOutOfRangeException">Pool <paramref name="size"/> must at least be one.</exception>
300+ public void SetPoolSize(int size)
301+ {
302+ if (size < 1)
303+ throw new ArgumentOutOfRangeException("size", "pool size must at least be one");
304+
305+ for (int i = 0; i < size - m_objectPool.Count; i++)
306+ {
307+ T item = FastObjectFactory<T>.CreateObjectFunction();
308+
309+ // Automatically handle life cycle if item implements support for this
310+ ISupportLifecycle lifecycleItem = item as ISupportLifecycle;
311+
312+ // Attach to dispose event so item can be automatically returned to the pool
313+ if (lifecycleItem != null)
314+ lifecycleItem.Disposed += LifecycleItem_Disposed;
315+
316+ m_objectPool.Enqueue(item);
317+ }
318+ }
319+
320+ /// <summary>
321+ /// Gets the number of items currently contained in the pool.
322+ /// </summary>
323+ /// <returns>The size of the pool.</returns>
324+ public int GetPoolSize()
325+ {
326+ return m_objectPool.Count;
327+ }
328+
329+ // Handler to automatically to return items to the queue
330+ private void LifecycleItem_Disposed(object sender, EventArgs e)
331+ {
332+ ReturnObject(sender as T);
333+ }
334+
335+ /// <summary>
336+ /// Default static instance which can be shared throughout the application.
337+ /// </summary>
338+ public static readonly ReusableObjectPool<T> Default = new ReusableObjectPool<T>();
339+ }
340+
341+ /// <summary>
342+ /// Represents a reusable object pool that can be used by an application.
343+ /// </summary>
344+ /// <remarks>
345+ /// <para>
346+ /// See <see cref="ReusableObjectPool{T}"/> for more details on using object pooling.
347+ /// </para>
348+ /// <para>
349+ /// <see cref="ReusableObjectPool"/> should be used when you only have the <see cref="Type"/> of an object available (such as when you are
350+ /// using reflection), otherwise you should use the generic <see cref="ReusableObjectPool{T}"/>.
351+ /// </para>
352+ /// </remarks>
353+ public class ReusableObjectPool
354+ {
355+ private static ConcurrentDictionary<Type, ConcurrentQueue<object>> s_objectPools = new ConcurrentDictionary<Type, ConcurrentQueue<object>>();
356+
357+ /// <summary>
358+ /// Gets an object from the pool, or creates a new one if no pool items are available.
359+ /// </summary>
360+ /// <param name="type">Type of object to get from pool.</param>
361+ /// <returns>An available object from the pool, or a new one if no pool items are available.</returns>
362+ /// <exception cref="InvalidOperationException"><paramref name="type"/> does not support parameterless public constructor.</exception>
363+ /// <remarks>
364+ /// If <paramref name="type"/> implements <see cref="ISupportLifecycle"/>, the pool will attach
365+ /// to the item's <see cref="ISupportLifecycle.Disposed"/> event such that the object can be automatically
366+ /// restored to the pool upon <see cref="IDisposable.Dispose"/>. It will be up to class implementors to
367+ /// make sure <see cref="ISupportLifecycle.Initialize"/> makes the class ready for use as this method will
368+ /// always be called for an object being taken from the pool.
369+ /// </remarks>
370+ public static object TakeObject(Type type)
371+ {
372+ return TakeObject<object>(type);
373+ }
374+
375+ /// <summary>
376+ /// Gets an object from the pool, or creates a new one if no pool items are available.
377+ /// </summary>
378+ /// <param name="type">Type of object to get from pool.</param>
379+ /// <typeparam name="T">Type of returned object to get from pool.</typeparam>
380+ /// <returns>An available object from the pool, or a new one if no pool items are available.</returns>
381+ /// <exception cref="InvalidOperationException">
382+ /// <paramref name="type"/> does not support parameterless public constructor -or-
383+ /// <paramref name="type"/> is not a subclass or interface implementation of function type definition.
384+ /// </exception>
385+ /// <remarks>
386+ /// <para>
387+ /// This function will validate that <typeparamref name="T"/> is related to <paramref name="type"/>.
388+ /// </para>
389+ /// <para>
390+ /// If <paramref name="type"/> implements <see cref="ISupportLifecycle"/>, the pool will attach
391+ /// to the item's <see cref="ISupportLifecycle.Disposed"/> event such that the object can be automatically
392+ /// restored to the pool upon <see cref="IDisposable.Dispose"/>. It will be up to class implementors to
393+ /// make sure <see cref="ISupportLifecycle.Initialize"/> makes the class ready for use as this method will
394+ /// always be called for an object being taken from the pool.
395+ /// </para>
396+ /// </remarks>
397+ public static T TakeObject<T>(Type type)
398+ {
399+ object item;
400+ bool newItem = false;
401+
402+ // Get or create object pool associated with specified type
403+ ConcurrentQueue<object> objectPool = s_objectPools.GetOrAdd(type, (objType) => new ConcurrentQueue<object>());
404+
405+ // Attempt to provide user with a queued item
406+ if (!objectPool.TryDequeue(out item))
407+ {
408+ // No items are available, create a new item for the object pool
409+ item = FastObjectFactory.GetCreateObjectFunction<T>(type)();
410+ newItem = true;
411+ }
412+
413+ // Automatically handle class life cycle if item implements support for this
414+ ISupportLifecycle lifecycleItem = item as ISupportLifecycle;
415+
416+ if (lifecycleItem != null)
417+ {
418+ // Attach to dispose event so item can be automatically returned to the pool
419+ if (newItem)
420+ lifecycleItem.Disposed += LifecycleItem_Disposed;
421+
422+ // Initialize or reinitialize (i.e., un-dispose) the item
423+ lifecycleItem.Initialize();
424+ }
425+
426+ return (T)item;
427+ }
428+
429+ /// <summary>
430+ /// Returns object to the pool.
431+ /// </summary>
432+ /// <param name="item">Reference to the object being returned.</param>
433+ /// <remarks>
434+ /// If type of <paramref name="item"/> implements <see cref="ISupportLifecycle"/>, the pool will automatically
435+ /// return the item to the pool when the <see cref="ISupportLifecycle.Disposed"/> event is raised, usually when
436+ /// the object's <see cref="IDisposable.Dispose"/> method is called.
437+ /// </remarks>
438+ public static void ReturnObject(object item)
439+ {
440+ if (item != null)
441+ {
442+ ConcurrentQueue<object> objectPool;
443+
444+ // Try to get object pool associated with the specified item's type
445+ if (s_objectPools.TryGetValue(item.GetType(), out objectPool))
446+ objectPool.Enqueue(item);
447+ }
448+ }
449+
450+ /// <summary>
451+ /// Releases all the objects currently cached in the specified pool.
452+ /// </summary>
453+ /// <param name="type">Type of pool to clear.</param>
454+ public static void Clear(Type type)
455+ {
456+ ConcurrentQueue<object> objectPool;
457+
458+ // Try to get object pool associated with the specified type
459+ if (s_objectPools.TryGetValue(type, out objectPool))
460+ {
461+ object item;
462+
463+ while (!objectPool.IsEmpty)
464+ {
465+ objectPool.TryDequeue(out item);
466+ }
467+ }
468+ }
469+
470+ /// <summary>
471+ /// Allocates the pool to the desired <paramref name="size"/>.
472+ /// </summary>
473+ /// <param name="type">Type of pool to initialize.</param>
474+ /// <param name="size">Desired pool size.</param>
475+ /// <exception cref="ArgumentOutOfRangeException">Pool <paramref name="size"/> must at least be one.</exception>
476+ public static void SetPoolSize(Type type, int size)
477+ {
478+ if (size < 1)
479+ throw new ArgumentOutOfRangeException("size", "pool size must at least be one");
480+
481+ // Get or create object pool associated with specified type
482+ ConcurrentQueue<object> objectPool = s_objectPools.GetOrAdd(type, (objType) => new ConcurrentQueue<object>());
483+
484+ for (int i = 0; i < size - objectPool.Count; i++)
485+ {
486+ object item = FastObjectFactory.GetCreateObjectFunction(type)();
487+
488+ // Automatically handle life cycle if item implements support for this
489+ ISupportLifecycle lifecycleItem = item as ISupportLifecycle;
490+
491+ // Attach to dispose event so item can be automatically returned to the pool
492+ if (lifecycleItem != null)
493+ lifecycleItem.Disposed += LifecycleItem_Disposed;
494+
495+ objectPool.Enqueue(item);
496+ }
497+ }
498+
499+ // Handler to automatically to return items to the queue
500+ private static void LifecycleItem_Disposed(object sender, EventArgs e)
501+ {
502+ ReturnObject(sender);
503+ }
504+ }
505+}

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