private void RunComplexTest(StaticPoolManager <int> testInst, int threadCount, int opCount, int pauseSpin, bool autoAddRemove) { Thread[] threads = new Thread[threadCount]; Barrier startBar = new Barrier(threadCount + 1); int opCountPerThread = opCount / threadCount; Action thAct = () => { Random localRand = new Random(Thread.CurrentThread.ManagedThreadId + Environment.TickCount); int pasueDiff = (int)Math.Ceiling(pauseSpin / 4.0); startBar.SignalAndWait(); int execOp = 0; while (execOp++ < opCountPerThread) { if (autoAddRemove && (testInst.ElementCount == 0 || localRand.Next(5) == 0)) { testInst.AddElement(execOp); } using (var el = testInst.Rent()) { if (autoAddRemove && testInst.ElementCount > 1 && localRand.Next(5) == 0) { testInst.RemoveElement(el); } int spinCount = localRand.Next(pauseSpin - pasueDiff, pauseSpin + pasueDiff); SpinWaitHelper.SpinWait(spinCount); } } if (autoAddRemove) { testInst.AddElement(execOp); } }; 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(); for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } Assert.AreEqual(testInst.ElementCount, testInst.FreeElementCount); }
public void SpinWaitOnNetCore31IsAlwaysNormalized() { for (int i = 0; i < 10; i++) { int normValue = SpinWaitHelper.GetSpinWaitNormalizationCoef(); Assert.AreEqual(1, normValue); Thread.Sleep(1); } }
public void SpinWaitPerformNormalizationInBackground() { while (!SpinWaitHelper.NormalizationCoefCalculated) { SpinWaitHelper.SpinWait(100); } this.TestContext.WriteLine($"Normalization coef: {SpinWaitHelper.NormalizationCoef}"); }
public void TestExecuteAndForget() { var command = new MockCommand(true); var processor = new MockCommandProcessor(); processor.Init(Assert.IsNull); processor.ExecuteAndForget(1, command); Assert.IsTrue(SpinWaitHelper.SpinWaitForCondition(() => command.CurrentState == false, 500)); //new state should be false }
public void SpinningNormalizedValidation() { while (!SpinWaitHelper.NormalizationCoefCalculated) { SpinWaitHelper.SpinWait(100); } SpinningNormalizedValidationCore(); SpinningNormalizedValidationCore(); SpinningNormalizedValidationCore(); }
private static TimeSpan TestObjectPoolWithSyncPrior(PrioritizedElementsContainer <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("PrioritizedElementsContainer. Elapsed = " + sw.ElapsedMilliseconds.ToString() + "ms"); return(sw.Elapsed); }
private void SpinningNormalizedValidationCore() { var sw = Stopwatch.StartNew(); for (int i = 0; i < 500; i++) { SpinWaitHelper.SpinWait(1000 * 1000 / 37); } sw.Stop(); TestContext.WriteLine($"Measured time: {sw.ElapsedMilliseconds}ms"); // Expect 500ms (can be large due to context switch) //Assert.IsTrue(sw.ElapsedMilliseconds > 400 && sw.ElapsedMilliseconds < 600, "Measured time: " + sw.ElapsedMilliseconds.ToString()); }
private void RunComplexTest(TestDynamicPool testInst, int threadCount, int opCount, int pauseSpin, bool faultElements) { Thread[] threads = new Thread[threadCount]; Barrier startBar = new Barrier(threadCount + 1); int opCountPerThread = opCount / threadCount; Action thAct = () => { Random localRand = new Random(Thread.CurrentThread.ManagedThreadId + Environment.TickCount); int pasueDiff = (int)Math.Ceiling(pauseSpin / 4.0); startBar.SignalAndWait(); int execOp = 0; while (execOp++ < opCountPerThread) { using (var el = testInst.Rent()) { if (faultElements && localRand.Next(10) == 0) { el.Element.MakeInvalid(); } int spinCount = localRand.Next(pauseSpin - pasueDiff, pauseSpin + pasueDiff); SpinWaitHelper.SpinWait(spinCount); } } }; 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(); for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } Assert.AreEqual(testInst.ElementCount, testInst.FreeElementCount); }
public void TestRun_With_Exception_OnCompleted() { using (var target = new ConsumerWorker <int, int>()) { Exception newEx = null; target.Init((k, i) => { }, ex => newEx = ex); var q = new MockQueue { 1 }; target.Run(q, w => { throw new ApplicationException("Test Exception"); }); Assert.IsTrue(SpinWaitHelper.SpinWaitForCondition(() => newEx != null, 1000)); Assert.IsInstanceOfType(newEx, typeof(ApplicationException)); } }
private static TimeSpan TestNewPool(Qoollo.Turbo.ObjectPools.ObjectPoolManager <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) { using (var el = pool.Rent()) { //Thread.Sleep(pauseSpin); SpinWaitHelper.SpinWait(pauseSpin); } } }; 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(pool.ToString() + ". Elapsed = " + sw.ElapsedMilliseconds.ToString() + "ms"); return(sw.Elapsed); }
public void AddTakeMultithreadTest() { const int ItemsCount = 10000; using (var queue = new BlockingQueue <int>()) using (var barrier = new Barrier(2)) { ConcurrentBag <int> bag = new ConcurrentBag <int>(); var task1 = Task.Run(() => { barrier.SignalAndWait(); Parallel.For(0, ItemsCount, val => { queue.Add(val); SpinWaitHelper.SpinWait(val % 16); }); }); var task2 = Task.Run(() => { barrier.SignalAndWait(); Parallel.For(0, 10000, val => { int res = 0; if (!queue.TryTake(out res, 10000)) { Assert.Fail("Value was expected in MemoryQueue"); } bag.Add(res); SpinWaitHelper.SpinWait((val + 5) % 16); }); }); Task.WaitAll(task1, task2); Assert.AreEqual(0, queue.Count); Assert.AreEqual(ItemsCount, bag.Count); var array = bag.ToArray(); Array.Sort(array); for (int i = 0; i < array.Length; i++) { Assert.AreEqual(i, array[i], "i != array[i]"); } } }
// ========================= private void AddWakesUpTest(LevelingQueue <int> queue) { while (queue.TryAdd(100)) { ; // Fill queue } if (queue.IsBackgroundTransferingEnabled) { SpinWait sw = new SpinWait(); while (queue.IsBackgroundInWork && sw.Count < 100) { sw.SpinOnce(); } for (int i = 0; i < 100; i++) { queue.TryAdd(100); SpinWaitHelper.SpinWait(12); } } Barrier bar = new Barrier(2); int addResult = 0; Task task = Task.Run(() => { bar.SignalAndWait(); AtomicSet(ref addResult, queue.TryAdd(-100, 60000)); }); bar.SignalAndWait(); Thread.Sleep(10); Assert.AreEqual(0, Volatile.Read(ref addResult)); queue.Take(); if (queue.AddingMode == LevelingQueueAddingMode.PreserveOrder && !queue.IsBackgroundTransferingEnabled) { int item; while (queue.TryTake(out item)) { ; } } TimingAssert.AreEqual(10000, 1, () => Volatile.Read(ref addResult)); task.Wait(); }
public void SpinWaitSmallFluctuation() { List <int> measureResults = new List <int>(); for (int i = 0; i < 10; i++) { measureResults.Add(SpinWaitHelper.GetSpinWaitNormalizationCoef()); Thread.Sleep(100); } int minMeasure = measureResults.Min(); int maxMeasure = measureResults.Max(); TestContext.WriteLine($"MinMeasure: {minMeasure}, MaxMeasure: {maxMeasure}"); // Fluctuation can actually be high in some scenarious //Assert.IsTrue(maxMeasure - minMeasure <= 1); }
public void AddTakeSequentialTest() { const int ItemsCount = 10000; using (var queue = new BlockingQueue <int>()) using (var barrier = new Barrier(2)) { List <int> bag = new List <int>(); var task1 = Task.Run(() => { barrier.SignalAndWait(); for (int val = 0; val < ItemsCount; val++) { queue.Add(val); SpinWaitHelper.SpinWait(val % 16); } }); var task2 = Task.Run(() => { barrier.SignalAndWait(); for (int val = 0; val < ItemsCount; val++) { int res = 0; if (!queue.TryTake(out res, 10000)) { Assert.Fail("Value was expected in MemoryQueue"); } bag.Add(res); SpinWaitHelper.SpinWait((val + 5) % 16); } }); Task.WaitAll(task1, task2); Assert.AreEqual(0, queue.Count); Assert.AreEqual(ItemsCount, bag.Count); for (int i = 0; i < bag.Count; i++) { Assert.AreEqual(i, bag[i], "i != bag[i]"); } } }
private static TimeSpan MeasureCountingProc(int count, int thCount, int spin) { int value = 0; Barrier barStart = new Barrier(thCount + 1); Barrier barEnd = new Barrier(thCount + 1); EntryCountingEvent inst = new EntryCountingEvent(); Action act = () => { barStart.SignalAndWait(); while (Interlocked.Increment(ref value) < count) { using (var guard = inst.TryEnter()) { SpinWaitHelper.SpinWait(spin); } } barEnd.SignalAndWait(); }; Thread[] threads = new Thread[thCount]; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(new ThreadStart(act)); threads[i].Start(); } barStart.SignalAndWait(); Stopwatch sw = Stopwatch.StartNew(); barEnd.SignalAndWait(); sw.Stop(); for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } inst.Dispose(); Console.WriteLine($"Counting. Elapsed = {sw.ElapsedMilliseconds}ms"); return(sw.Elapsed); }
// =================== private void RunWriteAbort(PersistentDiskQueueSegment <int> segment, int count, Random rnd) { Barrier bar = new Barrier(2); Exception observedEx = null; int added = 0; ThreadStart act = () => { bar.SignalAndWait(); int item = 1; try { while (segment.TryAdd(item++)) { Interlocked.Increment(ref added); } } catch (Exception ex) { if (!(ex is ThreadAbortException)) { Volatile.Write(ref observedEx, ex); } } Interlocked.Add(ref added, count); }; Thread th = new Thread(act); th.Start(); bar.SignalAndWait(); while (Volatile.Read(ref added) < count) { SpinWaitHelper.SpinWait(20); } SpinWaitHelper.SpinWait(rnd.Next(4000)); th.Abort(); th.Join(); if (observedEx != null) { throw observedEx; } }
public void TryAcceptWorkerMock() { var worker = new MockWorker(); var completed = new ManualResetEventSlim(false); var dequeueCount = new CountdownEvent(1); var target = new ConsumerQueue <int, int>(11, w => { Assert.AreSame(worker, w); completed.Set(); }, q => dequeueCount.Signal()); //test that correct instance passed target.Add(1); Task task = Task.Factory.StartNew(() => target.TryAcceptWorker(worker)); Assert.IsTrue(SpinWaitHelper.SpinWaitForCondition(() => target.IsBusy, 1000)); //should become busy when accept occurs task.Wait(); Assert.IsTrue(dequeueCount.Wait(1000)); //completed should be called Assert.IsTrue(completed.Wait(1000)); //completed should be called }
/// <summary> /// Perform a spin /// </summary> public void SpinOnce() { if (this.NextSpinWillYield) { int yieldThreshold = _yieldThreshold; if (yieldThreshold == 0) { yieldThreshold = DefaultYieldThreshold; } int num = (_count >= yieldThreshold) ? (_count - yieldThreshold) : _count; if (num % SLEEP_1_EVERY_HOW_MANY_TIMES == (SLEEP_1_EVERY_HOW_MANY_TIMES - 1)) { Thread.Sleep(1); } else { if (num % SLEEP_0_EVERY_HOW_MANY_TIMES == (SLEEP_0_EVERY_HOW_MANY_TIMES - 1)) { Thread.Sleep(0); } else { Thread.Yield(); } } } else { int spinCount = _singleSpinCount; if (spinCount == 0) { spinCount = DefaultSingleSpinCount; } SpinWaitHelper.SpinWait(spinCount * _count + spinCount); } this._count = ((this._count == int.MaxValue) ? 10 : (this._count + 1)); }
private void Create_Add_AndWaitForCompletion(bool suspendWorkers) { const int itemsTotal = 20; const int consumersTotal = 20; using (var countdownConsumer = new CountdownEvent(itemsTotal)) using (var countdownAdd = new CountdownEvent(itemsTotal)) { using (var target = new MockTaskPool(() => (k, i) => { Assert.AreEqual(k, i); countdownConsumer.Signal(); }, (k, i) => { Assert.AreEqual(k, i); countdownAdd.Signal(); }, Assert.IsNull, consumersTotal, suspendWorkers, false, 1000)) { Assert.AreEqual(consumersTotal, target.PoolSize); Task.Factory.StartNew(() => { for (int i = 0; i < itemsTotal; i++) { target.Add(i, i); } }); Assert.IsTrue(SpinWaitHelper.SpinWaitForCondition(() => target.PendingRequests > 0, 1000)); Assert.IsTrue(countdownAdd.Wait(5000)); //should invoke add callback within timeout Assert.IsTrue(countdownConsumer.Wait(5000)); //should invoke consumer within timeout Assert.IsTrue(SpinWaitHelper.SpinWaitForCondition(() => target.IndexSize == itemsTotal, 1000)); Assert.IsTrue(SpinWaitHelper.SpinWaitForCondition(() => target.PoolSize == consumersTotal, 10000)); Assert.AreEqual(0, target.PendingRequests); } } }
/// <summary> /// Custom spinning logic implementation. Tweaked for SemaphoreLight (roughly equivalent to .NET Core 3.0 SpinWait logic, better than .NET Framework SpinWait logic) /// </summary> /// <param name="spinNumber">Number of the spin</param> private static void SpinOnce(int spinNumber) { if (spinNumber < SPIN_YIELD_THRESHOLD) { SpinWaitHelper.SpinWait(8 + 2 * spinNumber); } else { if ((spinNumber - SPIN_YIELD_THRESHOLD) % SPIN_SLEEP0_PERIOD == (SPIN_SLEEP0_PERIOD - 1)) { Thread.Sleep(0); } else if ((spinNumber - SPIN_YIELD_THRESHOLD) % 2 == 1 && _processorCount > 1) { SpinWaitHelper.SpinWait(8); } else { Thread.Yield(); } } }
// ========================== private void PreserveOrderTest(LevelingQueue <int> queue, int elemCount) { Barrier bar = new Barrier(2); CancellationTokenSource cancelled = new CancellationTokenSource(); List <int> takenElems = new List <int>(elemCount + 1); Action addAction = () => { int curElem = 0; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); bar.SignalAndWait(); while (curElem < elemCount) { if (rnd.Next(100) == 0) { queue.AddForced(curElem); } else { queue.Add(curElem); } if (rnd.Next(100) == 0) { Thread.Yield(); } SpinWaitHelper.SpinWait(rnd.Next(12)); curElem++; } cancelled.Cancel(); }; StringBuilder badInfo = new StringBuilder(); Action takeAction = () => { Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); bar.SignalAndWait(); try { while (!cancelled.IsCancellationRequested) { takenElems.Add(queue.Take(cancelled.Token)); //if (takenElems[takenElems.Count - 1] != takenElems.Count - 1) // badInfo.Append("Is taken from high = " + queue.LastTakeTop.ToString()); if (rnd.Next(100) == 0) { Thread.Yield(); } SpinWaitHelper.SpinWait(rnd.Next(12)); } } catch (OperationCanceledException) { } int item = 0; while (queue.TryTake(out item)) { takenElems.Add(item); } }; var sw = System.Diagnostics.Stopwatch.StartNew(); Task addTask = Task.Factory.StartNew(addAction, TaskCreationOptions.LongRunning); Task takeTask = Task.Factory.StartNew(takeAction, TaskCreationOptions.LongRunning); Task.WaitAll(addTask, takeTask); Assert.AreEqual(elemCount, takenElems.Count); for (int i = 0; i < takenElems.Count; i++) { if (i != takenElems[i]) { Assert.AreEqual(i, takenElems[i], $"i != takenElems[i], nextItem = {takenElems[i + 1]}, badInfo = '{badInfo}'"); } } }
private static TimeSpan RunConcurrentMon(string name, int elemCount, int addThCount, int takeThCount, int addSpin, int takeSpin) { MonitorThreadSafeQueue <int> col = new MonitorThreadSafeQueue <int>(10000); CancellationTokenSource srcCancel = new CancellationTokenSource(); Thread[] addThreads = new Thread[addThCount]; Thread[] takeThreads = new Thread[takeThCount]; int addedElemCount = 0; List <int> globalList = new List <int>(); Barrier barierStart = new Barrier(1 + addThreads.Length + takeThreads.Length); Barrier barierAdders = new Barrier(1 + addThreads.Length); Barrier barierTakers = new Barrier(1 + takeThreads.Length); Action addAction = () => { barierStart.SignalAndWait(); int index = 0; while ((index = Interlocked.Increment(ref addedElemCount)) <= elemCount) { col.Add(index - 1); SpinWaitHelper.SpinWait(addSpin); } barierAdders.SignalAndWait(); }; Action takeAction = () => { CancellationToken myToken = srcCancel.Token; List <int> valList = new List <int>(elemCount / takeThCount + 100); barierStart.SignalAndWait(); try { while (!srcCancel.IsCancellationRequested) { int val = 0; val = col.Take(myToken); valList.Add(val); SpinWaitHelper.SpinWait(takeSpin); } } catch (OperationCanceledException) { } int val2 = 0; while (col.TryTake(out val2)) { valList.Add(val2); } barierTakers.SignalAndWait(); lock (globalList) { globalList.AddRange(valList); } }; for (int i = 0; i < addThreads.Length; i++) { addThreads[i] = new Thread(new ThreadStart(addAction)); } for (int i = 0; i < takeThreads.Length; i++) { takeThreads[i] = new Thread(new ThreadStart(takeAction)); } for (int i = 0; i < takeThreads.Length; i++) { takeThreads[i].Start(); } for (int i = 0; i < addThreads.Length; i++) { addThreads[i].Start(); } barierStart.SignalAndWait(); Stopwatch sw = Stopwatch.StartNew(); barierAdders.SignalAndWait(); srcCancel.Cancel(); barierTakers.SignalAndWait(); sw.Stop(); for (int i = 0; i < addThreads.Length; i++) { addThreads[i].Join(); } for (int i = 0; i < takeThreads.Length; i++) { takeThreads[i].Join(); } globalList.Sort(); if (globalList.Count != elemCount) { Console.WriteLine("Bad count"); } for (int i = 0; i < globalList.Count; i++) { if (globalList[i] != i) { Console.WriteLine("invalid elements"); break; } } if (name != null) { Console.WriteLine(name + ". MonQ. Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); } return(sw.Elapsed); }
// =================== private void PreserveOrderTest(PersistentDiskQueueSegment <int> segment, int elemCount) { Assert.IsTrue(elemCount <= segment.Capacity); Barrier bar = new Barrier(2); CancellationTokenSource cancelled = new CancellationTokenSource(); List <int> takenElems = new List <int>(elemCount + 1); Action addAction = () => { int curElem = 0; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); bar.SignalAndWait(); while (curElem < elemCount) { if (rnd.Next(100) == 0) { segment.AddForced(curElem); } else { Assert.IsTrue(segment.TryAdd(curElem)); } if (rnd.Next(100) == 0) { Thread.Yield(); } SpinWaitHelper.SpinWait(rnd.Next(12)); curElem++; } cancelled.Cancel(); }; Action takeAction = () => { Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); bar.SignalAndWait(); try { while (!cancelled.IsCancellationRequested) { int curItem = 0; if (segment.TryTake(out curItem)) { takenElems.Add(curItem); } if (rnd.Next(100) == 0) { Thread.Yield(); } SpinWaitHelper.SpinWait(rnd.Next(12)); } } catch (OperationCanceledException) { } int item = 0; while (segment.TryTake(out item)) { takenElems.Add(item); } }; var sw = System.Diagnostics.Stopwatch.StartNew(); Task addTask = Task.Factory.StartNew(addAction, TaskCreationOptions.LongRunning); Task takeTask = Task.Factory.StartNew(takeAction, TaskCreationOptions.LongRunning); Task.WaitAll(addTask, takeTask); Assert.AreEqual(elemCount, takenElems.Count); for (int i = 0; i < takenElems.Count; i++) { if (i != takenElems[i]) { Assert.AreEqual(i, takenElems[i], $"i != takenElems[i], nextItem = {takenElems[i + 1]}"); } } }
public void ProcessorDetectionIsNotFail() { TestContext.WriteLine(SpinWaitHelper.GetProcessorKind().ToString()); }
public void FrameworkNotSupportSpinWaitNormalization() { Assert.IsFalse(SpinWaitHelper.IsFrameworkSupportSpinWaitNormalization()); }
// ========================= private void RunComplexTest(PersistentDiskQueueSegment <int> segment, int elemCount, int thCount) { Assert.IsTrue(elemCount <= segment.Capacity); int atomicRandom = 0; int trackElemCount = elemCount; int addFinished = 0; Thread[] threadsTake = new Thread[thCount]; Thread[] threadsAdd = new Thread[thCount]; CancellationTokenSource tokSrc = new CancellationTokenSource(); List <int> global = new List <int>(elemCount); Action addAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); while (true) { int item = Interlocked.Decrement(ref trackElemCount); if (item < 0) { break; } if (rnd.Next(100) == 0) { segment.AddForced(item); } else { Assert.IsTrue(segment.TryAdd(item)); } int sleepTime = rnd.Next(12); int tmpItem = 0; if (segment.TryPeek(out tmpItem) && tmpItem == item) { sleepTime += 12; } if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } Interlocked.Increment(ref addFinished); }; Action takeAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); List <int> data = new List <int>(); try { while (Volatile.Read(ref addFinished) < thCount) { int tmp = 0; if (segment.TryTake(out tmp)) { data.Add((int)tmp); } int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } } catch (OperationCanceledException) { } int tmp2; while (segment.TryTake(out tmp2)) { data.Add((int)tmp2); } lock (global) global.AddRange(data); }; for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i] = new Thread(new ThreadStart(takeAction)); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i] = new Thread(new ThreadStart(addAction)); } for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Start(); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Start(); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Join(); } tokSrc.Cancel(); for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Join(); } Assert.AreEqual(elemCount, global.Count); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i]); } }
private void RunComplexTest(ConcurrentBatchingQueue <int> q, int elemCount, int thCount) { int atomicRandom = 0; int trackElemCount = elemCount; int addFinished = 0; Thread[] threadsTake = new Thread[thCount]; Thread[] threadsAdd = new Thread[thCount]; Thread enumerateThread = null; CancellationTokenSource tokSrc = new CancellationTokenSource(); List <int> global = new List <int>(elemCount); Action addAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); while (true) { int item = Interlocked.Decrement(ref trackElemCount); if (item < 0) { break; } q.Enqueue(item); int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } Interlocked.Increment(ref addFinished); }; Action takeAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); List <int> data = new List <int>(); try { while (Volatile.Read(ref addFinished) < thCount) { int[] tmp; if (q.TryDequeue(out tmp)) { data.AddRange(tmp); } int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } } catch (OperationCanceledException) { } int[] tmp2; while (q.TryDequeue(out tmp2)) { data.AddRange(tmp2); } q.CompleteCurrentBatch(); while (q.TryDequeue(out tmp2)) { data.AddRange(tmp2); } lock (global) global.AddRange(data); }; Action enumerateAction = () => { Random rnd = new Random(); while (Volatile.Read(ref addFinished) < thCount && !tokSrc.IsCancellationRequested) { int count = 0; foreach (long item in q) { count++; } Thread.Sleep(count > 100 ? 0 : 1); if (rnd.Next(100) == 1) { q.CompleteCurrentBatch(); } } }; for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i] = new Thread(new ThreadStart(takeAction)); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i] = new Thread(new ThreadStart(addAction)); } enumerateThread = new Thread(new ThreadStart(enumerateAction)); for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Start(); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Start(); } enumerateThread.Start(); for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Join(); } tokSrc.Cancel(); for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Join(); } enumerateThread.Join(); Assert.AreEqual(elemCount, global.Count); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i]); } }
public void TestFullCycle() { PartialThreadBlocker inst = new PartialThreadBlocker(0); Barrier startBar = new Barrier(8 + 1); int exitedCount = 0; CancellationTokenSource tokenSrc = new CancellationTokenSource(); Thread[] threads = new Thread[8]; Func <int> sleepThCount = () => { int result = 0; foreach (var th in threads) { if ((th.ThreadState & ThreadState.WaitSleepJoin) != 0) { result++; } } return(result); }; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(() => { startBar.SignalAndWait(); while (!tokenSrc.IsCancellationRequested) { inst.Wait(); SpinWaitHelper.SpinWait(1200); Thread.Yield(); } Interlocked.Increment(ref exitedCount); }); threads[i].Start(); } startBar.SignalAndWait(); for (int i = 0; i < threads.Length; i++) { TimingAssert.AreEqual(5000, i, sleepThCount, "UP. Sleeping thread count != i"); TimingAssert.AreEqual(5000, i, () => inst.RealWaiterCount, "UP. RealWaiterCount != i"); TimingAssert.AreEqual(5000, i, () => inst.ExpectedWaiterCount, "UP. ExpectedWaiterCount != i"); inst.AddExpectedWaiterCount(1); Thread.Sleep(10); } TimingAssert.AreEqual(5000, threads.Length, sleepThCount); TimingAssert.AreEqual(5000, threads.Length, () => inst.RealWaiterCount); TimingAssert.AreEqual(5000, threads.Length, () => inst.ExpectedWaiterCount); for (int i = threads.Length; i > 0; i--) { TimingAssert.AreEqual(5000, i, sleepThCount); TimingAssert.AreEqual(5000, i, () => inst.RealWaiterCount); TimingAssert.AreEqual(5000, i, () => inst.ExpectedWaiterCount); inst.SubstractExpectedWaiterCount(1); Thread.Sleep(10); } TimingAssert.AreEqual(5000, 0, sleepThCount, "Sleeping thread count != 0"); TimingAssert.AreEqual(5000, 0, () => inst.RealWaiterCount, "RealWaiterCount != 0"); TimingAssert.AreEqual(5000, 0, () => inst.ExpectedWaiterCount, "ExpectedWaiterCount != 0"); tokenSrc.Cancel(); TimingAssert.AreEqual(5000, threads.Length, () => Volatile.Read(ref exitedCount)); }
public static void RunTest() { //TstBQ(); //Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)1; SpinWaitHelper.WaitUntilNormalizationCoefCalculated(); Console.WriteLine($"SpinWait norm coef = {SpinWaitHelper.NormalizationCoef}"); for (int i = 0; i < 10; i++) { RunConcurrentBC("1, 1", 5000000, 1, 1, 20, 20); Free(); RunConcurrentBC("4, 4", 5000000, 4, 4, 20, 20); Free(); RunConcurrentBC("16, 1", 5000000, 16, 1, 20, 20); Free(); RunConcurrentBC("1, 16", 5000000, 1, 16, 20, 20); Free(); RunConcurrentBC("16, 16", 5000000, 16, 16, 20, 20); Free(); Console.WriteLine(); RunConcurrentBQ("1, 1", 5000000, 1, 1, 20, 20); Free(); RunConcurrentBQ("4, 4", 5000000, 4, 4, 20, 20); Free(); RunConcurrentBQ("16, 1", 5000000, 16, 1, 20, 20); Free(); RunConcurrentBQ("1, 16", 5000000, 1, 16, 20, 20); Free(); RunConcurrentBQ("16, 16", 5000000, 16, 16, 20, 20); Free(); Console.WriteLine(); RunConcurrentCondVar("1, 1", 5000000, 1, 1, 20, 20); Free(); RunConcurrentCondVar("4, 4", 5000000, 4, 4, 20, 20); Free(); RunConcurrentCondVar("16, 1", 5000000, 16, 1, 20, 20); Free(); RunConcurrentCondVar("1, 16", 5000000, 1, 16, 20, 20); Free(); RunConcurrentCondVar("16, 16", 5000000, 16, 16, 20, 20); Free(); Console.WriteLine(); RunConcurrentMon("1, 1", 5000000, 1, 1, 20, 20); Free(); RunConcurrentMon("4, 4", 5000000, 4, 4, 20, 20); Free(); RunConcurrentMon("16, 1", 5000000, 16, 1, 20, 20); Free(); RunConcurrentMon("1, 16", 5000000, 1, 16, 20, 20); Free(); RunConcurrentMon("16, 16", 5000000, 16, 16, 20, 20); Free(); //RunConcurrentBC("Simple", 5000000, /*Environment.ProcessorCount */ 2, 2, 10, 100);//100 / Environment.ProcessorCount, 101); //Free(); //RunConcurrentBQ("Simple", 5000000, /*Environment.ProcessorCount */ 2, 2, 10, 100);//100 / Environment.ProcessorCount, 101); //Free(); //RunConcurrentBC("OverConcurrency", 5000000, /*4 * Environment.ProcessorCount*/ 8, 8, 0, 0);//100 / Environment.ProcessorCount, 101); //Free(); //RunConcurrentBQ("OverConcurrency", 5000000, /*4 * Environment.ProcessorCount*/ 8, 8, 0, 0);//100 / Environment.ProcessorCount, 101); //Free(); //RunConcurrentBC("OverConcurrency fix", 5000000, /*4 * Environment.ProcessorCount*/ 16, 16, 0, 0); //Free(); //RunConcurrentBQ("OverConcurrency fix", 5000000, /*4 * Environment.ProcessorCount*/ 16, 16, 0, 0); //Free(); Console.WriteLine(); } }
private void RunComplexTest(SemaphoreLight sem, int elemCount, int thCount) { int atomicRandom = 0; int trackElemCount = elemCount; int waitedTimesCount = 0; int addFinished = 0; Thread[] threadsTake = new Thread[thCount]; Thread[] threadsAdd = new Thread[thCount]; CancellationTokenSource tokSrc = new CancellationTokenSource(); Action addAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); while (true) { int item = Interlocked.Decrement(ref trackElemCount); if (item < 0) { break; } sem.Release(); int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } Interlocked.Increment(ref addFinished); }; Action takeAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); try { while (Volatile.Read(ref addFinished) < thCount) { sem.Wait(tokSrc.Token); Interlocked.Increment(ref waitedTimesCount); int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } } catch (OperationCanceledException) { } TestContext.WriteLine("One take thread exit main cycle"); while (sem.Wait(0)) { Interlocked.Increment(ref waitedTimesCount); } }; for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i] = new Thread(new ThreadStart(takeAction)); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i] = new Thread(new ThreadStart(addAction)); } for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Start(); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Start(); } TestContext.WriteLine("All threads started"); for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Join(); } TestContext.WriteLine("All add threads stopped"); tokSrc.Cancel(); TestContext.WriteLine("Cancell called"); for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Join(); } TestContext.WriteLine("All take threads stopped"); Assert.AreEqual(elemCount, waitedTimesCount); }