protected override void Dispose(bool disposing) { if (ExternallyOwned) { ThrowHelper.ThrowNotSupportedException(); } if (disposing) { var pool = Pool; if (pool != null) { pool.ReturnInternal(this, clearMemory: !TypeHelper <T> .IsPinnable); // pool calls Dispose(false) if a bucket is full return; } // not pooled, doing finalization work now GC.SuppressFinalize(this); } // Finalization AtomicCounter.Dispose(ref CounterRef); Debug.Assert(!_isPooled); _poolIdx = default; // we still could add this to the pool of free pinned slices that are backed by an existing slab var pooledToFreeSlicesPool = _slicesPool.Return(this); if (pooledToFreeSlicesPool) { return; } var array = Interlocked.Exchange(ref _array, null); if (array != null) { ClearAfterDispose(); Debug.Assert(_handle.IsAllocated); #pragma warning disable 618 _slab.Decrement(); _handle.Free(); #pragma warning restore 618 } else { ThrowDisposed <ArrayMemorySlice <T> >(); } Debug.Assert(!_handle.IsAllocated); }
protected override void Dispose(bool disposing) { if (_externallyOwned) { ThrowHelper.ThrowNotSupportedException(); } EnsureNotRetainedAndNotDisposed(); // disposing == false when finalizing and detected that non pooled if (disposing) { TryReturnThisToPoolOrFinalize(); } else { Debug.Assert(!_isPooled); _pool = null; // we still could add this to the pool of free pinned slices that are backed by an existing slab var pooledToFreeSlicesPool = _slicesPool.Return(this); if (pooledToFreeSlicesPool) { return; } Counter.Dispose(); AtomicCounterService.ReleaseCounter(Counter); ClearAfterDispose(); // destroy the object and release resources var array = Interlocked.Exchange(ref _array, null); if (array != null) { Debug.Assert(_handle.IsAllocated); #pragma warning disable 618 _slab.Decrement(); _handle.Free(); #pragma warning restore 618 } else { ThrowDisposed <ArrayMemory <T> >(); } Debug.Assert(!_handle.IsAllocated); } }
public void PoolUnbalancedRentReturn() { const int perCoreCapacity = 50; Func <DummyPoolable> dummyFactory = () => new DummyPoolable(); var perCoreLockedObjectPool = new LockedObjectPool <DummyPoolable>(dummyFactory, perCoreCapacity, allocateOnEmpty: false); var queues = Enumerable.Range(0, 4) .Select(x => new SingleProducerSingleConsumerQueue <DummyPoolable>()).ToArray(); var cts = new CancellationTokenSource(); var totalCount = 0L; Task[] producers = new Task[queues.Length]; Task[] consumers = new Task[queues.Length]; var sw = Stopwatch.StartNew(); for (int i = 0; i < queues.Length; i++) { var queue = queues[i]; producers[i] = Task.Factory.StartNew(() => { var count = 0L; while (!cts.IsCancellationRequested) { var item = perCoreLockedObjectPool.Rent(); if (item != null) { queue.Enqueue(item); count++; } } Interlocked.Add(ref totalCount, count); }); consumers[i] = Task.Factory.StartNew(() => { var count = 0L; while (!cts.IsCancellationRequested) { if (queue.TryDequeue(out var item)) { perCoreLockedObjectPool.Return(item); count++; } } Interlocked.Add(ref totalCount, count); }); } Thread.Sleep(5_000); cts.Cancel(); Task.WaitAll(producers); Task.WaitAll(consumers); sw.Stop(); Console.WriteLine( $"MOPS: {(totalCount / 1000000.0) / (sw.ElapsedMilliseconds / 1000.0):N2}, Total count: {totalCount:N0}, elapsed: {sw.ElapsedMilliseconds:N0}"); }