/// <summary> /// Returns/adds an object to the pool so it can be reused. /// </summary> /// <param name="value"></param> /// <remarks> /// <para>Items will be returned to the pool if it is not full, otherwise no action is taken and no error is reported.</para> /// <para>If the policy for the pool specifies <see cref="PooledItemInitialization.AsyncReturn"/> the item will be queued for re-intialisation on a background thread before being returned to the pool, control will return to the caller once the item has been queued even if it has not yet been fully re-initialised and returned to the pool.</para> /// <para>If the item is NOT returned to the pool, and {T} implements <see cref="System.IDisposable"/>, the instance will be disposed before the method returns.</para> /// <para>Calling this method on a disposed pool will dispose the returned item if it supports <see cref="IDisposable"/>, but takes no other action and throws no error.</para> /// <para>This method is 'thread safe', though it is possible for multiple threads returning items at the same time to add items beyond the maximum pool size. This should be rare and have few ill effects. Over time the pool will likely return to it's normal size.</para> /// </remarks> /// <exception cref="ArgumentNullException">Thrown if the <paramref name="value"/> is null.</exception> /// <exception cref="InvalidOperationException">Thrown if the <see cref="PoolPolicy{T}.ErrorOnIncorrectUsage"/> is true and the same instance already exists in the pool.</exception> public override void Add(T value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } if (IsDisposed) { SafeDispose(value); return; } if (ShouldReturnToPool(value)) { if (PoolPolicy.InitializationPolicy == PooledItemInitialization.AsyncReturn) { SafeAddToReinitialiseQueue(value); } else { if (PoolPolicy.InitializationPolicy == PooledItemInitialization.Return && PoolPolicy.ReinitializeObject != null) { PoolPolicy.ReinitializeObject(value); } _Pool.Add(value); Interlocked.Increment(ref _PoolInstancesCount); } } else { SafeDispose(value); } }
/// <summary> /// Gets an item from the pool. /// </summary> /// <remarks> /// <para>If the pool is empty when the request is made, a new item is instantiated and returned. Otherwise an instance from the pool will be used.</para> /// </remarks> /// <returns>Returns an instance of {T} from the pool, or a new instance if the pool is empty.</returns> /// <exception cref="ObjectDisposedException">Thrown if the pool has been disposed.</exception> public override T Take() { CheckDisposed(); T retVal = null; if (_PoolItemIndex >= 0) { retVal = _PoolItems[_PoolItemIndex]; _PoolItems[_PoolItemIndex] = null; _PoolItemIndex--; if (retVal != null && PoolPolicy.InitializationPolicy == PooledItemInitialization.Take && PoolPolicy.ReinitializeObject != null) { PoolPolicy.ReinitializeObject(retVal); } } if (retVal == null) { retVal = PoolPolicy.Factory(this); } return(retVal); }
private void ReinitialiseAndReturnToPoolOrDispose(T value) { if (ShouldReturnToPool(value)) { PoolPolicy.ReinitializeObject(value); _Pool.Add(value); Interlocked.Increment(ref _PoolInstancesCount); } else { SafeDispose(value); } }
private bool ReinitialiseObject(T item) { try { PoolPolicy.ReinitializeObject(item); return(true); } catch (Exception ex) { OnReinitialiseError(new ReinitialiseErrorEventArgs <T>(ex, item)); SafeDispose(item); } return(false); }
/// <summary> /// Full constructor. /// </summary> /// <param name="poolPolicy">A <seealso cref="PoolPolicy{T}"/> instance containing configuration information for the pool.</param> /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="poolPolicy"/> argument is null.</exception> /// <exception cref="System.ArgumentException">Thrown if the <see cref="PoolPolicy{T}.Factory"/> property of the <paramref name="poolPolicy"/> argument is null.</exception> /// <exception cref="System.ArgumentException">Thrown if the <see cref="PoolPolicy{T}.InitializationPolicy"/> property is set to <see cref="PooledItemInitialization.AsyncReturn"/>.</exception> /// <exception cref="System.ArgumentException">Thrown if the <see cref="PoolPolicy{T}.MaximumPoolSize"/> property is less than or equal to zero.</exception> public UnsynchronizedPool(PoolPolicy <T> poolPolicy) : base(poolPolicy) { if (poolPolicy.InitializationPolicy == PooledItemInitialization.AsyncReturn) { throw new ArgumentException("poolPolicy.Factory cannot be PooledItemInitialization.AsyncReturn.", nameof(poolPolicy)); } if (poolPolicy.MaximumPoolSize <= 0) { throw new ArgumentException("A maximum pool size must be specified.", nameof(poolPolicy)); } _PoolItemIndex = -1; _PoolItems = new T[poolPolicy.MaximumPoolSize]; }
/// <summary> /// Full constructor. /// </summary> /// <param name="poolPolicy">A <seealso cref="PoolPolicy{T}"/> instance containing configuration information for the pool.</param> /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="poolPolicy"/> argument is null.</exception> /// <exception cref="System.ArgumentException">Thrown if the <see cref="PoolPolicy{T}.Factory"/> property of the <paramref name="poolPolicy"/> argument is null.</exception> protected PoolBase(PoolPolicy <T> poolPolicy) { if (poolPolicy == null) { throw new ArgumentNullException(nameof(poolPolicy)); } if (poolPolicy.Factory == null) { throw new ArgumentException("poolPolicy.Factory cannot be null"); } _IsPooledTypeWrapped = ReflectionUtils.IsTypeWrapped(typeof(T)); _IsPooledTypeDisposable = ReflectionUtils.IsTypeDisposable(typeof(T), _IsPooledTypeWrapped); _PoolPolicy = poolPolicy; }
/// <summary> /// Full constructor. /// </summary> /// <param name="poolPolicy">A <seealso cref="PoolPolicy{T}"/> instance containing configuration information for the pool.</param> /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="poolPolicy"/> argument is null.</exception> /// <exception cref="System.ArgumentException">Thrown if the <see cref="PoolPolicy{T}.Factory"/> property of the <paramref name="poolPolicy"/> argument is null.</exception> public Pool(PoolPolicy <T> poolPolicy) : base(poolPolicy) { _Pool = new System.Collections.Concurrent.ConcurrentBag <T>(); if (PoolPolicy.InitializationPolicy == PooledItemInitialization.AsyncReturn) { _ItemsToInitialise = new System.Collections.Concurrent.BlockingCollection <T>(); #if SUPPORTS_THREADS _ReinitialiseThread = new System.Threading.Thread(this.BackgroundReinitialise); _ReinitialiseThread.Name = this.GetType().FullName + " Background Reinitialise"; _ReinitialiseThread.IsBackground = true; _ReinitialiseThread.Start(); #else System.Threading.Tasks.Task.Factory.StartNew(this.BackgroundReinitialise, System.Threading.Tasks.TaskCreationOptions.LongRunning); #endif } }
/// <summary> /// Expands the pool up by the <paramref name="increment"/> value, but not past it's maximum size, with pre-generated instances. /// </summary> /// <param name="increment"></param> public override void Expand(int increment) { CheckDisposed(); if (increment <= 0) { return; } int createdCount = 0; while (createdCount < increment && !IsPoolFull()) { AddCore(PoolPolicy.Factory(this)); createdCount++; } }
/// <summary> /// Creates as many new items as specified by <paramref name="increment"/> and adds them to the pool, but not over it's maximum capacity. /// </summary> /// <param name="increment">The maximum number of items to pre-allocate and add to the pool.</param> /// <remarks> /// <para>This method is 'thread safe', though it is possible under certain race conditons for the pool to go beyond it's configured maximum size by a few items.</para> /// <para>If <paramref name="increment"/> is zero or less the method returns without doing anything</para> /// </remarks> /// <exception cref="System.ObjectDisposedException">Thrown if this method is called on a disposed pool.</exception> public override void Expand(int increment) { CheckDisposed(); if (increment <= 0) { return; } int createdCount = 0; while (createdCount < increment && !IsPoolFull()) { _Pool.Add(PoolPolicy.Factory(this)); Interlocked.Increment(ref _PoolInstancesCount); createdCount++; } }
private void BackgroundReinitialise() { T item = default(T); while (!_ItemsToInitialise.IsCompleted) { try { item = _ItemsToInitialise.Take(); } catch (InvalidOperationException) { if (_ItemsToInitialise.IsCompleted) { return; } } if (item != null) { if (IsDisposed) { SafeDispose(item); } else { if (PoolPolicy.ReinitializeObject != null) { PoolPolicy.ReinitializeObject(item); } if (ShouldReturnToPool(item)) { _Pool.Add(item); Interlocked.Increment(ref _PoolInstancesCount); } } } } }
/// <summary> /// Returns/adds an object to the pool so it can be reused. /// </summary> /// <param name="value"></param> /// <remarks> /// <para>Items will be returned to the pool if it is not full, otherwise no action is taken and no error is reported.</para> /// <para>If the item is NOT returned to the pool, and {T} implements <see cref="System.IDisposable"/>, the instance will be disposed before the method returns.</para> /// <para>Calling this method on a disposed pool will dispose the returned item if it supports <see cref="IDisposable"/>, but takes no other action and throws no error.</para> /// </remarks> /// <exception cref="ArgumentNullException">Thrown if the <paramref name="value"/> is null.</exception> /// <exception cref="InvalidOperationException">Thrown if the <see cref="PoolPolicy{T}.ErrorOnIncorrectUsage"/> is true and the same instance already exists in the pool.</exception> public override void Add(T value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } if (!IsDisposed && ShouldReturnToPool(value)) { if (PoolPolicy.InitializationPolicy == PooledItemInitialization.Return && PoolPolicy.ReinitializeObject != null) { PoolPolicy.ReinitializeObject(value); } AddCore(value); } else { SafeDispose(value); } }
/// <summary> /// Gets an item from the pool. /// </summary> /// <remarks> /// <para>If the pool is empty when the request is made, a new item is instantiated and returned. Otherwise an instance from the pool will be used.</para> /// <para>This method is thread safe.</para> /// </remarks> /// <returns>Returns an instance of {T} from the pool, or a new instance if the pool is empty.</returns> /// <exception cref="ObjectDisposedException">Thrown if the pool has been disposed.</exception> public override T Take() { CheckDisposed(); T retVal; if (_Pool.TryTake(out retVal)) { Interlocked.Decrement(ref _PoolInstancesCount); if (PoolPolicy.InitializationPolicy == PooledItemInitialization.Take && PoolPolicy.ReinitializeObject != null) { PoolPolicy.ReinitializeObject(retVal); } } else { retVal = PoolPolicy.Factory(this); } return(retVal); }
public Pool(PoolPolicy <T> poolPolicy) : base(poolPolicy) { ExceptionHelper.ThrowYoureDoingItWrong(); }