/// <summary> /// <see cref="DynamicPoolManager{TElem}"/> constructor /// </summary> /// <param name="minElementCount">Minimum number of elements that should always be in pool</param> /// <param name="maxElementCount">Maximum number of elements in pool</param> /// <param name="name">Name for the current <see cref="DynamicPoolManager{TElem}"/> instance</param> /// <param name="trimPeriod">Period in milliseconds to estimate the load level and to reduce the number of elements in accordance with it (-1 - do not preform contraction)</param> /// <param name="getRetryTimeout">Interval in milliseconds between attempts to create a new element (used when a new element fails to create)</param> public DynamicPoolManager(int minElementCount, int maxElementCount, string name, int trimPeriod, int getRetryTimeout) { if (minElementCount < 0) { throw new ArgumentOutOfRangeException(nameof(minElementCount)); } if (maxElementCount <= 0 || maxElementCount >= ((1 << 16) - 1)) { throw new ArgumentOutOfRangeException(nameof(maxElementCount)); } if (maxElementCount < minElementCount) { throw new ArgumentException($"{nameof(maxElementCount)} cannot be less than minElementCount", nameof(maxElementCount)); } if (getRetryTimeout <= 0) { throw new ArgumentException($"{nameof(getRetryTimeout)} should be positive", nameof(getRetryTimeout)); } _name = name ?? this.GetType().GetCSFullName(); _minElementCount = minElementCount; _maxElementCount = maxElementCount; _getRetryTimeout = getRetryTimeout; _trimPeriod = trimPeriod > 0 ? trimPeriod : int.MaxValue; _reservedCount = 0; _usedElementTracker = new UsedElementTracker(_trimPeriod); _elementsContainer = new SimpleElementsContainer <TElem>(); _stoppedEvent = new ManualResetEventSlim(false); _disposeCancellation = new CancellationTokenSource(); Profiling.Profiler.ObjectPoolCreated(this.Name); }
public void TakeDestroyReleaseWorkAsRemove() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { for (int i = 0; i < 10; i++) { testInst.Add(i, new PoolOperations(), true); } for (int i = 0; i < 10; i++) { var item = testInst.Take(); item.MarkElementDestroyed(); testInst.Release(item); Assert.IsTrue(item.IsRemoved); Assert.IsTrue(item.IsRemoved); Assert.AreEqual(10 - i - 1, testInst.AvailableCount); Assert.AreEqual(10 - i - 1, testInst.Count); } } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
public void TestTakeBlocks() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); CancellationTokenSource tokSrc = new CancellationTokenSource(); bool wasCancelled = false; bool wasEntered = false; bool wasExited = false; Task.Run(() => { try { Volatile.Write(ref wasEntered, true); PoolElementWrapper <int> item; testInst.TryTake(out item, -1, tokSrc.Token); } catch (OperationCanceledException) { Volatile.Write(ref wasCancelled, true); } Volatile.Write(ref wasExited, true); }); TimingAssert.IsTrue(10000, () => Volatile.Read(ref wasEntered)); Thread.Sleep(100); Assert.IsFalse(Volatile.Read(ref wasExited)); tokSrc.Cancel(); TimingAssert.IsTrue(10000, () => Volatile.Read(ref wasExited)); Assert.IsTrue(Volatile.Read(ref wasCancelled)); }
/// <summary> /// <see cref="StaticPoolManager{TElem}"/> constructor /// </summary> /// <param name="name">Name for the current <see cref="StaticPoolManager{TElem}"/> instance</param> /// <param name="destroyAction">The action that will be performed to destroy each element after removal ('null' means no action)</param> public StaticPoolManager(string name, Action <TElem> destroyAction) { _name = name ?? this.GetType().GetCSFullName(); _destroyAction = destroyAction; _elementsContainer = new SimpleElementsContainer <TElem>(); _stoppedEvent = new ManualResetEventSlim(false); _disposeCancellation = new CancellationTokenSource(); Profiling.Profiler.ObjectPoolCreated(this.Name); }
private static TimeSpan TestObjectPoolWithLListSimple(SimpleElementsContainer <PoolElem> pool, int threadCount, int opCount, int pauseSpin) { Thread[] threads = new Thread[threadCount]; Barrier startBar = new Barrier(threadCount + 1); int opCountPerThread = opCount / threadCount; Action thAct = () => { startBar.SignalAndWait(); int execOp = 0; while (execOp++ < opCountPerThread) { PoolElementWrapper <PoolElem> el = null; try { el = pool.Take(); //Thread.Sleep(pauseSpin); SpinWaitHelper.SpinWait(pauseSpin); } finally { pool.Release(el); } } }; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(new ThreadStart(thAct)); } for (int i = 0; i < threads.Length; i++) { threads[i].Start(); } startBar.SignalAndWait(); Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } sw.Stop(); Console.WriteLine("ObjectPoolWithLListSimple. Elapsed = " + sw.ElapsedMilliseconds.ToString() + "ms"); return(sw.Elapsed); }
private static void RunTestObjectPoolWithLListSimple(int threadCount, int elemCount, int opCount, int pauseSpin) { SimpleElementsContainer <PoolElem> pool = new SimpleElementsContainer <PoolElem>(); for (int i = 0; i < elemCount; i++) { pool.Add(new PoolElem(), new PoolElemOpSup(), true); } TestObjectPoolWithLListSimple(pool, threadCount, opCount, pauseSpin); PoolElementWrapper <PoolElem> tmp; while (pool.TryTake(out tmp, 0, new CancellationToken())) { tmp.MarkElementDestroyed(); pool.Release(tmp); } }
public void ComplexTest() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { for (int i = 0; i < 1; i++) { testInst.Add(i, new PoolOperations(), true); } TestContext.WriteLine("ComplexTest started"); RunComplexTest(testInst, Environment.ProcessorCount, 100000, 10); TestContext.WriteLine("ComplexTest phase 1 finished"); for (int i = testInst.Count; i < Environment.ProcessorCount; i++) { testInst.Add(i, new PoolOperations(), true); } RunComplexTest(testInst, Environment.ProcessorCount, 1000000, 10); TestContext.WriteLine("ComplexTest phase 2 finished"); for (int i = testInst.Count; i < 2 * Environment.ProcessorCount; i++) { testInst.Add(i, new PoolOperations(), true); } RunComplexTest(testInst, Environment.ProcessorCount, 1000000, 10); TestContext.WriteLine("ComplexTest phase 3 finished"); } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
public void TestAddElementAndNotMakeAvailable() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { Assert.AreEqual(0, testInst.Count); Assert.AreEqual(0, testInst.AvailableCount); var wrapper = testInst.Add(100, new PoolOperations(), false); Assert.IsNotNull(wrapper); Assert.IsTrue(wrapper.IsBusy); Assert.AreEqual(100, wrapper.Element); Assert.AreEqual(1, testInst.Count); Assert.AreEqual(0, testInst.AvailableCount); } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
public void TestRescanWorks() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { for (int i = 0; i < 10; i++) { testInst.Add(i, new PoolOperations(), true); } testInst.ProcessAllElements(o => o.MarkElementDestroyed()); testInst.RescanContainer(); Assert.AreEqual(0, testInst.Count); Assert.AreEqual(0, testInst.AvailableCount); } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
public void TestTakeUntilEmpty() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { for (int i = 0; i < 10; i++) { testInst.Add(i, new PoolOperations(), true); } List <PoolElementWrapper <int> > takenElems = new List <PoolElementWrapper <int> >(); PoolElementWrapper <int> item; for (int i = 0; i < 10; i++) { bool takeRes = testInst.TryTake(out item, 0, new CancellationToken()); takenElems.Add(item); Assert.IsTrue(takeRes); Assert.IsNotNull(item); Assert.IsTrue(item.IsBusy); } Assert.AreEqual(0, testInst.AvailableCount); bool takeResO = testInst.TryTake(out item, 0, new CancellationToken()); Assert.IsFalse(takeResO); for (int i = 0; i < takenElems.Count; i++) { testInst.Release(takenElems[i]); } } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
public void TestSimpleTakeRelease() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { for (int i = 0; i < 10; i++) { testInst.Add(i, new PoolOperations(), true); } Assert.AreEqual(10, testInst.Count); Assert.AreEqual(10, testInst.AvailableCount); var item = testInst.Take(); Assert.IsNotNull(item); Assert.IsTrue(item.Element >= 0 && item.Element < 10); Assert.IsTrue(item.IsBusy); Assert.IsFalse(item.IsElementDestroyed); Assert.AreEqual(10, testInst.Count); Assert.AreEqual(9, testInst.AvailableCount); testInst.Release(item); Assert.IsFalse(item.IsBusy); Assert.AreEqual(10, testInst.Count); Assert.AreEqual(10, testInst.AvailableCount); } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
public void TestRemoveOnTake() { SimpleElementsContainer <int> testInst = new SimpleElementsContainer <int>(); try { for (int i = 0; i < 10; i++) { testInst.Add(i, new PoolOperations(), true); } testInst.ProcessAllElements(o => o.MarkElementDestroyed()); PoolElementWrapper <int> item; bool takeResult = testInst.TryTake(out item, 0, new CancellationToken()); Assert.IsFalse(takeResult); Assert.AreEqual(0, testInst.Count); } finally { testInst.ProcessAllElements(o => o.MarkElementDestroyed()); } }
private void RunComplexTest(SimpleElementsContainer <int> testInst, int threadCount, int opCount, int pauseSpin) { Assert.AreEqual(testInst.AvailableCount, testInst.Count); Thread[] threads = new Thread[threadCount]; Barrier startBar = new Barrier(threadCount + 1); int opCountPerThread = opCount / threadCount; Action thAct = () => { startBar.SignalAndWait(); TestContext.WriteLine("Inside thread. Signal and wait passed"); try { int execOp = 0; while (execOp++ < opCountPerThread) { PoolElementWrapper <int> item = null; try { item = testInst.Take(); //Thread.Sleep(pauseSpin); Thread.SpinWait(pauseSpin); } finally { testInst.Release(item); } } } catch (Exception ex) { TestContext.WriteLine("Unhandled exception: " + ex.ToString()); throw; } }; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(new ThreadStart(thAct)); } TestContext.WriteLine("Threads created"); for (int i = 0; i < threads.Length; i++) { threads[i].Start(); } TestContext.WriteLine("Threads started"); startBar.SignalAndWait(); TestContext.WriteLine("Threads before join"); for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } TestContext.WriteLine("All threads stopped"); Assert.AreEqual(testInst.AvailableCount, testInst.Count); }