private void RunReadAbort(PersistentDiskQueueSegment <int> segment, int count, Random rnd) { Barrier bar = new Barrier(2); Exception observedEx = null; int taken = 0; ThreadStart act = () => { bar.SignalAndWait(); int item = 1; try { while (segment.TryTake(out item)) { Interlocked.Increment(ref taken); } } catch (Exception ex) { if (!(ex is ThreadAbortException)) { Volatile.Write(ref observedEx, ex); } } Interlocked.Add(ref taken, count); }; Thread th = new Thread(act); th.Start(); bar.SignalAndWait(); while (Volatile.Read(ref taken) < count) { SpinWaitHelper.SpinWait(20); } SpinWaitHelper.SpinWait(rnd.Next(4000)); th.Abort(); th.Join(); if (observedEx != null) { throw observedEx; } }
/// <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 static TimeSpan MeasureNormalProc(int count, int thCount, int spin) { int value = 0; Barrier barStart = new Barrier(thCount + 1); Barrier barEnd = new Barrier(thCount + 1); Action act = () => { barStart.SignalAndWait(); while (Interlocked.Increment(ref value) < count) { 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(); } Console.WriteLine($"Normal. Elapsed = {sw.ElapsedMilliseconds}ms"); return(sw.Elapsed); }
/// <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 RunTestOnPool(DynamicThreadPool pool, int totalTaskCount, int taskSpinCount, int spawnThreadCount, int spawnSpinTime, bool spawnFromPool) { Random rndGenerator = new Random(); int executedTaskCounter = 0; int completedTaskCount = 0; Action taskAction = null; taskAction = () => { int curTaskSpinCount = taskSpinCount; lock (rndGenerator) curTaskSpinCount = rndGenerator.Next(taskSpinCount); SpinWaitHelper.SpinWait(curTaskSpinCount); if (spawnFromPool) { if (Interlocked.Increment(ref executedTaskCounter) <= totalTaskCount) { pool.Run(taskAction); } } Interlocked.Increment(ref completedTaskCount); }; Barrier bar = new Barrier(spawnThreadCount + 1); Random spawnRndGenerator = new Random(); Thread[] spawnThreads = new Thread[spawnThreadCount]; ThreadStart spawnAction = () => { bar.SignalAndWait(); while (Interlocked.Increment(ref executedTaskCounter) <= totalTaskCount) { pool.Run(taskAction); int curSpawnSpinCount = spawnSpinTime; lock (spawnRndGenerator) curSpawnSpinCount = spawnRndGenerator.Next(spawnSpinTime); SpinWaitHelper.SpinWait(curSpawnSpinCount); } }; for (int i = 0; i < spawnThreads.Length; i++) { spawnThreads[i] = new Thread(spawnAction); } for (int i = 0; i < spawnThreads.Length; i++) { spawnThreads[i].Start(); } bar.SignalAndWait(); TimingAssert.AreEqual(60 * 1000, totalTaskCount, () => Volatile.Read(ref completedTaskCount)); }
private void RunConcurrentUseWithDispose(int maxPoolElemCount, int threadCount, int opCount, bool faultElements = true) { using (TestDynamicPool testInst = new TestDynamicPool(0, maxPoolElemCount)) { Thread[] threads = new Thread[threadCount]; Barrier startBar = new Barrier(threadCount + 1); int totalExecutedOpCount = 0; Action thAct = () => { Random localRand = new Random(Thread.CurrentThread.ManagedThreadId + Environment.TickCount); startBar.SignalAndWait(); try { while (true) { int curSpinTime = localRand.Next(0, 2000); Interlocked.Increment(ref totalExecutedOpCount); using (var el = testInst.Rent(60 * 1000, throwOnUnavail: true)) { if (faultElements && localRand.Next(10) == 0) { el.Element.MakeInvalid(); } if (curSpinTime > 1000) { Thread.Sleep(0); } else { SpinWaitHelper.SpinWait(curSpinTime); } } } } catch (ObjectDisposedException) { } catch (CantRetrieveElementException) { } }; 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(); while (Volatile.Read(ref totalExecutedOpCount) < opCount) { Thread.Sleep(1); } testInst.Dispose(); for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } Assert.AreEqual(testInst.ElementCount, testInst.FreeElementCount, "testInst.ElementCount != testInst.FreeElementCount"); Assert.AreEqual(testInst.ElementsCreated, testInst.ElementsDestroyed, "ElementsCreated != ElementsDestroyed"); } }
private void TestHeavyRandomAddRemoveCore(int operationCount, int threadCount, int spinCount, bool doAutoCompaction) { SparceArrayStorage <object> testInst = new SparceArrayStorage <object>(doAutoCompaction); List <object> activeElements = new List <object>(); int randomSeed = 0; int operationPerThread = operationCount / threadCount; Thread[] threads = new Thread[threadCount]; Action act = () => { Random rnd = new Random(Interlocked.Increment(ref randomSeed) + Environment.TickCount); List <object> localElements = new List <object>(); for (int i = 0; i < operationPerThread; i++) { int operationId = doAutoCompaction ? rnd.Next(2) : rnd.Next(3); if (operationId == 0) { object obj = new object(); localElements.Add(obj); testInst.Add(obj); } else if (operationId == 1) { if (localElements.Count > 0) { object obj = localElements[rnd.Next(localElements.Count)]; localElements.Remove(obj); testInst.Remove(obj); } } else { if (localElements.Count > 0) { object obj = localElements[rnd.Next(localElements.Count)]; int compactionIndex = testInst.IndexOf(obj); testInst.CompactElementAt(ref compactionIndex); } } int mySpinCount = spinCount / 2 + rnd.Next(spinCount / 2); SpinWaitHelper.SpinWait(mySpinCount); } lock (activeElements) { activeElements.AddRange(localElements); } }; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(new ThreadStart(act)); } for (int i = 0; i < threads.Length; i++) { threads[i].Start(); } for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } Assert.AreEqual(activeElements.Count, testInst.Count, "activeElements.Count != testInst.Count"); List <object> elementsFromTestInst = new List <object>(); for (int i = 0; i < testInst.RawData.Length; i++) { if (testInst.RawData[i] != null) { elementsFromTestInst.Add(testInst.RawData[i]); } } Assert.AreEqual(elementsFromTestInst.Count, testInst.Count, "elementsFromTestInst.Count != testInst.Count"); foreach (var elem in activeElements) { Assert.IsTrue(elementsFromTestInst.Contains(elem), "!elementsFromTestInst.Contains(elem)"); } }
private static TimeSpan TestSemaphoreLight(string name, int elemCount, int addThCount, int takeThCount, int addSpin, int takeSpin) { SemaphoreLight sem = new SemaphoreLight(0, int.MaxValue); CancellationTokenSource srcCancel = new CancellationTokenSource(); Thread[] addThreads = new Thread[addThCount]; Thread[] takeThreads = new Thread[takeThCount]; int addedElemCount = 0; 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) { sem.Release(); SpinWaitHelper.SpinWait(addSpin); } barierAdders.SignalAndWait(); }; Action takeAction = () => { CancellationToken myToken = srcCancel.Token; barierStart.SignalAndWait(); try { while (!srcCancel.IsCancellationRequested) { sem.Wait(myToken); SpinWaitHelper.SpinWait(takeSpin); } } catch (OperationCanceledException) { } while (sem.Wait(0)) { } barierTakers.SignalAndWait(); }; 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(); } Console.WriteLine(name + ". SemaphoreLight. Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); return(sw.Elapsed); }
private void RunComplexTest(SparceArrayStorage <PoolElementWrapper <int> > storage, IndexedStackElementStorage <int> stack, int elemCount, int thCount) { int atomicRandom = 0; int trackElemCount = elemCount; int addFinished = 0; Thread[] threadsTake = new Thread[thCount]; Thread[] threadsAdd = new Thread[thCount]; CancellationTokenSource tokSrc = new CancellationTokenSource(); BlockingCollection <PoolElementWrapper <int> > freeElements = new BlockingCollection <PoolElementWrapper <int> >(); foreach (var elem in storage.RawData) { if (elem != null) { freeElements.Add(elem); } } int[] addedCountArray = new int[storage.Count]; int[] takenCountArray = new int[storage.Count]; 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; } var elem = freeElements.Take(); stack.Add(elem); Interlocked.Increment(ref addedCountArray[storage.IndexOf(elem)]); 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) { PoolElementWrapper <int> tmp = null; if (stack.TryTake(out tmp)) { freeElements.Add(tmp); Interlocked.Increment(ref takenCountArray[storage.IndexOf(tmp)]); } int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } } catch (OperationCanceledException) { } PoolElementWrapper <int> tmp2 = null; while (stack.TryTake(out tmp2)) { freeElements.Add(tmp2); Interlocked.Increment(ref takenCountArray[storage.IndexOf(tmp2)]); } }; 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(storage.Count, freeElements.Count); Assert.IsTrue(stack.HeadIndex < 0); for (int i = 0; i < storage.Count; i++) { Assert.IsTrue(addedCountArray[i] == takenCountArray[i], "Added count != taken count"); } }
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]); } }
// ========================= 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]); } }
/// <summary> /// Blocks the current thread if it is required /// </summary> /// <param name="timeout">Waiting timeout in milliseconds</param> /// <param name="token">Cancellation token</param> /// <returns>True if the current thread successfully passed the <see cref="PartialThreadBlocker"/> (false - exited by timeout)</returns> public bool Wait(int timeout, CancellationToken token) { token.ThrowIfCancellationRequested(); if (timeout < 0) { timeout = Timeout.Infinite; } if (_realWaiterCount >= _expectedWaiterCount) { return(true); } if (timeout == 0) { return(false); } uint startTime = 0; int currentTime = Timeout.Infinite; if (timeout != Timeout.Infinite) { startTime = TimeoutHelper.GetTimestamp(); } for (int i = 0; i < 10; i++) { if (_realWaiterCount >= _expectedWaiterCount) { return(true); } if (i == 5) { Thread.Yield(); } else { SpinWaitHelper.SpinWait(16 + 4 * i); } } using (CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this)) { lock (_lockObj) { if (_realWaiterCount < _expectedWaiterCount) { try { _realWaiterCount++; while (_realWaiterCount <= _expectedWaiterCount) { token.ThrowIfCancellationRequested(); if (timeout != Timeout.Infinite) { currentTime = TimeoutHelper.UpdateTimeout(startTime, timeout); if (currentTime <= 0) { return(false); } } if (!Monitor.Wait(_lockObj, currentTime)) { return(false); } } } finally { _realWaiterCount--; } } } } return(true); }
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)); }
private static TimeSpan RunConcurrentDiskQFile(string name, int elemCount, int addThCount, int takeThCount, int addSpin, int takeSpin) { if (Directory.Exists("dummy")) { Directory.Delete("dummy", true); } Directory.CreateDirectory("dummy"); DiskQueue <int> col = new DiskQueue <int>("dummy", new NonPersistentDiskQueueSegmentFactory <int>(10000, "prefix", new ItemSerializer(), 256, 16), 10, true); //DiskQueue<int> col = new DiskQueue<int>("dummy", // new PersistentDiskQueueSegmentFactory<int>(10000, "prefix", new ItemSerializer(), false, false, 1000, 64), // 10, true); 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 + ". DiskQFile. Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); } col.Dispose(); return(sw.Elapsed); }
// ====================== private void ValidateCountTest(DiskQueue <int> queue, CommonSegmentFactory <int> factory, int elemCount) { Barrier bar = new Barrier(2); CancellationTokenSource cancelled = new CancellationTokenSource(); List <int> takenElems = new List <int>(elemCount + 1); AtomicBool needSync = new AtomicBool(); Action addAction = () => { int curElem = 0; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); bar.SignalAndWait(); while (curElem < elemCount) { bool itemAdded = true; if (rnd.Next(100) == 0) { queue.AddForced(curElem); } else if (needSync.Value) { itemAdded = queue.TryAdd(curElem); } else { queue.Add(curElem); } if (rnd.Next(100) == 0) { Thread.Yield(); } SpinWaitHelper.SpinWait(rnd.Next(12)); if (itemAdded) { curElem++; } Assert.IsTrue(itemAdded || needSync.Value); if (curElem % 1000 == 0) { needSync.Value = true; } if (needSync.Value && bar.ParticipantsRemaining == 1) { Assert.AreEqual(factory.SumCountFromAllocated(), queue.Count); needSync.Value = false; bar.SignalAndWait(); } } cancelled.Cancel(); }; Action takeAction = () => { Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); bar.SignalAndWait(); try { while (!cancelled.IsCancellationRequested) { takenElems.Add(queue.Take(cancelled.Token)); if (rnd.Next(100) == 0) { Thread.Yield(); } SpinWaitHelper.SpinWait(rnd.Next(12)); if (needSync.Value) { bar.SignalAndWait(cancelled.Token); } } } 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]}"); } } }
private void ConcurrentPackageWithTimeoutTestCore(int addThreads, int itemCount, int batchSize, int boundedCapacityInBatches) { int atomicRandom = 0; BlockingBatchingQueue <int> col = new BlockingBatchingQueue <int>(batchSize: batchSize, boundedCapacityInBatches: boundedCapacityInBatches); Barrier bar = new Barrier(1 + 1 + addThreads); CancellationTokenSource cancelToken = new CancellationTokenSource(); Thread[] threadsAdd = new Thread[addThreads]; Thread[] threadsTake = new Thread[1]; List <int> takenItems = new List <int>(); int itemsCounter = itemCount; Action addAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * addThreads * 2); bar.SignalAndWait(); while (true) { int val = Interlocked.Decrement(ref itemsCounter); if (val < 0) { break; } col.Add(val); int delay = (int)(((double)val / itemCount) * 100); if (delay > 0) { SpinWaitHelper.SpinWait(rnd.Next(delay)); } } }; Action takeAction = () => { var token = cancelToken.Token; int[] items = null; bar.SignalAndWait(); try { while (!cancelToken.IsCancellationRequested) { if (col.TryTake(out items, 5, token)) { takenItems.AddRange(items); } else { col.CompleteCurrentBatch(); } } } catch (OperationCanceledException) { } while (col.TryTake(out items)) { takenItems.AddRange(items); } col.CompleteCurrentBatch(); if (col.TryTake(out items)) { takenItems.AddRange(items); } }; 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(); } bar.SignalAndWait(); for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Join(); } cancelToken.Cancel(); for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Join(); } takenItems.Sort(); for (int i = 0; i < takenItems.Count; i++) { Assert.AreEqual(i, takenItems[i]); } }
private void TestCancellationNotCorruptDataCore(int batchSize, int boundedCapacityInBatches) { BlockingBatchingQueue <long> col = new BlockingBatchingQueue <long>(batchSize: batchSize, boundedCapacityInBatches: boundedCapacityInBatches); Barrier bar = new Barrier(4); CancellationTokenSource cancelToken = new CancellationTokenSource(); CancellationTokenSource temporaryCancelTokenAdd = new CancellationTokenSource(); CancellationTokenSource temporaryCancelTokenTake = new CancellationTokenSource(); List <long> takenItems = new List <long>(); Task addTask = Task.Run(() => { Random rnd = new Random(); bar.SignalAndWait(); long data = 0; CancellationToken token = temporaryCancelTokenAdd.Token; while (!cancelToken.IsCancellationRequested) { try { col.Add(data, token); data++; } catch (OperationCanceledException) { token = temporaryCancelTokenAdd.Token; } } }); Task takeTask = Task.Run(() => { bar.SignalAndWait(); CancellationToken token = temporaryCancelTokenTake.Token; while (!cancelToken.IsCancellationRequested) { try { long[] itemsT = col.Take(token); takenItems.AddRange(itemsT); } catch (OperationCanceledException) { token = temporaryCancelTokenTake.Token; } if (takenItems.Count > int.MaxValue / 2) { cancelToken.Cancel(); } } }); Task cancelTask = Task.Run(() => { Random rnd = new Random(); bar.SignalAndWait(); while (!cancelToken.IsCancellationRequested) { if (rnd.Next(100) == 1) { temporaryCancelTokenAdd.Cancel(); temporaryCancelTokenAdd = new CancellationTokenSource(); } if (rnd.Next(100) == 1) { temporaryCancelTokenTake.Cancel(); temporaryCancelTokenTake = new CancellationTokenSource(); } SpinWaitHelper.SpinWait(rnd.Next(12)); } }); bar.SignalAndWait(); Thread.Sleep(500); cancelToken.Cancel(); temporaryCancelTokenAdd.Cancel(); temporaryCancelTokenTake.Cancel(); Task.WaitAll(addTask, takeTask, cancelTask); while (col.TryTake(out long[] itemsF)) { takenItems.AddRange(itemsF); } col.CompleteCurrentBatch(); if (col.TryTake(out long[] itemsFF)) { takenItems.AddRange(itemsFF); } for (int i = 0; i < takenItems.Count; i++) { Assert.AreEqual(i, takenItems[i]); } }
public void AddTakeSequentialTest() { const int ItemsCount = 50000; var memQueue = new MemoryQueue <long>(); var converter = new TypeConverter(); using (var queue = new TransformationQueue <int, long>(memQueue, converter)) 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++) { if (val % 10 == 0) { queue.Add(val); } else if (val % 10 == 1) { Assert.IsTrue(queue.TryAdd(val)); } else if (val % 10 == 2) { Assert.IsTrue(queue.TryAdd(val, 1000)); } else if (val % 10 == 3) { Assert.IsTrue(queue.TryAdd(val, TimeSpan.FromSeconds(1))); } else if (val % 10 == 4) { Assert.IsTrue(queue.TryAdd(val, 1000, new CancellationToken())); } else if (val % 10 == 5) { queue.AddForced(val); } else { queue.Add(val, new CancellationToken()); } SpinWaitHelper.SpinWait(val % 16); } }); var task2 = Task.Run(() => { barrier.SignalAndWait(); for (int val = 0; val < ItemsCount; val++) { int res = 0; if (val % 10 == 0) { Assert.IsTrue(queue.TryTake(out res, 10000), "Value was expected 1"); } else if (val % 10 == 1) { Assert.IsTrue(queue.TryTake(out res, 10000, new CancellationToken()), "Value was expected 2"); } else { Assert.IsTrue(queue.TryTake(out res, TimeSpan.FromSeconds(10)), "Value was expected 3"); } 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]"); } Assert.AreEqual(0, memQueue.Count); Assert.AreEqual(ItemsCount, converter.ConvertNum); Assert.AreEqual(ItemsCount, converter.ConvertBackNum); } }
private void RunThreadPoolConcurrentQueueTest(ThreadPoolConcurrentQueue q, int elemCount, int thCount) { int atomicRandom = 0; int trackElemCount = elemCount; int addFinished = 0; Thread[] threadsAdd = new Thread[thCount]; Thread[] threadsRemove = new Thread[thCount]; 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.Add(new TestThreadPoolItem(item)); int sleepTime = rnd.Next(120); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } Interlocked.Increment(ref addFinished); }; Action removeAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); List <int> data = new List <int>(); while (Volatile.Read(ref addFinished) < thCount) { ThreadPoolWorkItem tmp; if (q.TryTake(out tmp)) { data.Add((TestThreadPoolItem)tmp); } int sleepTime = rnd.Next(120); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } ThreadPoolWorkItem tmp2; while (q.TryTake(out tmp2)) { data.Add((TestThreadPoolItem)tmp2); } lock (global) global.AddRange(data); }; for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i] = new Thread(new ThreadStart(addAction)); } for (int i = 0; i < threadsRemove.Length; i++) { threadsRemove[i] = new Thread(new ThreadStart(removeAction)); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Start(); } for (int i = 0; i < threadsRemove.Length; i++) { threadsRemove[i].Start(); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Join(); } for (int i = 0; i < threadsRemove.Length; i++) { threadsRemove[i].Join(); } Assert.AreEqual(elemCount, global.Count); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i]); } }
// ========================== 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 void RunComplexTestOnCustom(int threadCount, int queueSize, int testElemCount, int addThreadCount, int procSpinWaitCount, int addSleepMs) { List <int> processedItems = new List <int>(testElemCount + 1); int currentItem = 0; Random rnd = new Random(); MemoryQueue <int> mem1 = new MemoryQueue <int>(100); MemoryQueue <int> mem2 = new MemoryQueue <int>(queueSize); LevelingQueue <int> lvl = new LevelingQueue <int>(mem1, mem2); using (DelegateQueueAsyncProcessor <int> proc = new DelegateQueueAsyncProcessor <int>(threadCount, lvl, "name", (elem, token) => { int curSpinCount = 0; lock (rnd) curSpinCount = rnd.Next(procSpinWaitCount); SpinWaitHelper.SpinWait(curSpinCount); lock (processedItems) processedItems.Add(elem); })) { Action addAction = () => { while (true) { int curVal = Interlocked.Increment(ref currentItem); if (curVal > testElemCount) { break; } proc.Add(curVal - 1); if (addSleepMs > 0) { SmartSleep(addSleepMs); } } }; Thread[] addThreads = new Thread[addThreadCount]; for (int i = 0; i < addThreads.Length; i++) { addThreads[i] = new Thread(new ThreadStart(addAction)); } for (int i = 0; i < addThreads.Length; i++) { addThreads[i].Start(); } proc.Start(); Assert.IsTrue(proc.IsWork); for (int i = 0; i < addThreads.Length; i++) { addThreads[i].Join(); } proc.Stop(true, true, true); Assert.AreEqual(testElemCount, processedItems.Count); processedItems.Sort(); for (int i = 0; i < processedItems.Count; i++) { Assert.AreEqual(i, processedItems[i]); } } }
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); }
private static TimeSpan RunTestOnPool(Qoollo.Turbo.Threading.ThreadPools.ThreadPoolBase pool, TestConfiguration config, bool waitForCompletion = true) { var taskActiveTimeDev = (int)(config.ActiveTaskAvgTime.Ticks / 4); var taskPassiveTimeDev = (int)(config.PassiveTaskAvgTime.Ticks / 4); Random rndGenerator = new Random(); int executedTaskCounter = 0; int completedTaskCount = 0; Action taskAction = null; taskAction = () => { if (config.PassiveTaskAvgTime > TimeSpan.Zero) { TimeSpan taskTime = config.PassiveTaskAvgTime; if (config.UseDeviance) { lock (rndGenerator) taskTime += TimeSpan.FromTicks(rndGenerator.Next(-taskPassiveTimeDev, taskPassiveTimeDev)); } int taskTimeMs = CalcRandSleep(rndGenerator, taskTime.TotalMilliseconds); if (taskTimeMs > 0) { Thread.Sleep(taskTimeMs); } else if (taskTimeMs == 0) { Thread.Yield(); } } // ---- if (config.ActiveTaskAvgTime > TimeSpan.Zero) { TimeSpan taskTime = config.ActiveTaskAvgTime; if (config.UseDeviance) { lock (rndGenerator) taskTime += TimeSpan.FromTicks(rndGenerator.Next(-taskActiveTimeDev, taskActiveTimeDev)); } int taskTimeMs = CalcRandSleep(rndGenerator, taskTime.TotalMilliseconds); if (taskTimeMs > 0) { Stopwatch sw111 = Stopwatch.StartNew(); while (sw111.ElapsedMilliseconds < taskTimeMs) { SpinWaitHelper.SpinWait(2000); } } else if (taskTimeMs == 0) { Thread.Yield(); } } // ---- if (config.SpawnFromPool) { if (Interlocked.Increment(ref executedTaskCounter) <= config.TaskCount) { //pool.RunAsTask(taskAction); pool.Run(taskAction); } } Interlocked.Increment(ref completedTaskCount); }; Barrier bar = new Barrier(config.SpawnThreadCount + 1); Random spawnRndGenerator = new Random(); int spawnTimeDev = (int)(config.SpawnPeriod.Ticks / 4); Thread[] spawnThreads = new Thread[config.SpawnThreadCount]; ThreadStart spawnAction = () => { bar.SignalAndWait(); long expectedSleep = 0; long realSleep = 0; int curSpawned = 0; while ((curSpawned = Interlocked.Increment(ref executedTaskCounter)) <= config.TaskCount) { //pool.RunAsTask(taskAction); pool.Run(taskAction); TimeSpan spawnSleep = config.SpawnPeriod; if (config.UseDeviance) { lock (spawnRndGenerator) spawnSleep += TimeSpan.FromTicks(spawnRndGenerator.Next(-spawnTimeDev, spawnTimeDev)); } int spawnSleepMs = CalcRandSleep(spawnRndGenerator, spawnSleep.TotalMilliseconds); if (spawnSleepMs > 0) { expectedSleep += spawnSleepMs; int startTick = Environment.TickCount; if (realSleep <= expectedSleep) { Thread.Sleep(spawnSleepMs); } realSleep += (Environment.TickCount - startTick); } } }; for (int i = 0; i < spawnThreads.Length; i++) { spawnThreads[i] = new Thread(spawnAction); } for (int i = 0; i < spawnThreads.Length; i++) { spawnThreads[i].Start(); } bar.SignalAndWait(); Stopwatch sw = Stopwatch.StartNew(); if (waitForCompletion) { SpinWait.SpinUntil(() => Volatile.Read(ref completedTaskCount) >= config.TaskCount); } else { SpinWait.SpinUntil(() => Volatile.Read(ref executedTaskCounter) >= config.TaskCount); } sw.Stop(); if (waitForCompletion && completedTaskCount != config.TaskCount) { throw new Exception("completedTaskCount != config.TaskCount"); } 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 long ConvertBack(int item) { SpinWaitHelper.SpinWait(8); return(item); }
private void RunComplexTest(ThreadPoolGlobalQueue q, int elemCount, int thCount) { int atomicRandom = 0; int trackElemCount = elemCount; int addFinished = 0; Thread[] threadsMain = new Thread[thCount]; Thread[] threadsAdditional = new Thread[thCount]; CancellationTokenSource tokSrc = new CancellationTokenSource(); List <int> global = new List <int>(elemCount); Action additionalAction = () => { 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.Add(new TestThreadPoolItem(item)); int sleepTime = rnd.Next(120); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } if (rnd.Next(100) == 0) { q.RequestCapacityExtension(50); } } Interlocked.Increment(ref addFinished); }; Action mainAction = () => { 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) { ThreadPoolWorkItem tmp = null; if (q.TryTake(out tmp, -1, tokSrc.Token, true)) { data.Add((TestThreadPoolItem)tmp); } int sleepTime = rnd.Next(100); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } } catch (OperationCanceledException) { } ThreadPoolWorkItem tmp2; while (q.TryTake(out tmp2, 0, CancellationToken.None, true)) { data.Add((TestThreadPoolItem)tmp2); } lock (global) global.AddRange(data); }; Task.Delay(1000).ContinueWith(t => q.RequestCapacityExtension(50)); for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i] = new Thread(new ThreadStart(mainAction)); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i] = new Thread(new ThreadStart(additionalAction)); } for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i].Start(); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i].Start(); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i].Join(); } tokSrc.Cancel(); for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i].Join(); } Assert.AreEqual(elemCount, global.Count); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i]); } }
private void RunComplexTest(PrioritizedElementsContainer <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); SpinWaitHelper.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); }
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 RunComplexTest(MutuallyExclusivePrimitive inst, int workCount, int workSpin, int sleepProbability) { Barrier barrier = new Barrier(4); CancellationTokenSource globalCancellation = new CancellationTokenSource(); ManualResetEventSlim alwaysNotSet = new ManualResetEventSlim(false); int workPerformGate1 = 0; int workPerformGate2 = 0; int workCompletedCount = 0; int gate1Executed = 0; int gate2Executed = 0; Action <Random, CancellationToken, int> doWork = (Random rnd, CancellationToken token, int gate) => { try { if (gate == 1) { Interlocked.Increment(ref workPerformGate1); if (Volatile.Read(ref workPerformGate2) != 0) { throw new Exception("Mutual exclusive logic is broken"); } Interlocked.Increment(ref gate1Executed); } else { Interlocked.Increment(ref workPerformGate2); if (Volatile.Read(ref workPerformGate1) != 0) { throw new Exception("Mutual exclusive logic is broken"); } Interlocked.Increment(ref gate2Executed); } if (rnd.Next(sleepProbability) == 0) { alwaysNotSet.Wait(1, token); } else { int spin = rnd.Next(0, workSpin); SpinWaitHelper.SpinWait(spin); } } finally { if (gate == 1) { Interlocked.Decrement(ref workPerformGate1); } else { Interlocked.Decrement(ref workPerformGate2); } } }; Action <int> worker = (int gate) => { var token = globalCancellation.Token; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); barrier.SignalAndWait(); while (!token.IsCancellationRequested) { try { using (var guard = gate == 1 ? inst.EnterMain(Timeout.Infinite, token) : inst.EnterBackground(Timeout.Infinite, token)) { using (var linked = CancellationTokenSource.CreateLinkedTokenSource(token, guard.Token)) { doWork(rnd, token, gate); } } int spin = rnd.Next(0, workSpin); SpinWaitHelper.SpinWait(spin); } catch (OperationCanceledException) { } int localWorkCompl = Interlocked.Increment(ref workCompletedCount); if (localWorkCompl > workCount) { globalCancellation.Cancel(); } } }; Action switcher = () => { var token = globalCancellation.Token; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); barrier.SignalAndWait(); while (!token.IsCancellationRequested) { int sleep = rnd.Next(workSpin); Thread.Sleep(sleep); inst.AllowBackgroundGate(); sleep = rnd.Next(workSpin); Thread.Sleep(sleep); inst.DisallowBackgroundGate(); } }; Task workerThread1 = Task.Factory.StartNew(() => worker(1), TaskCreationOptions.LongRunning); Task workerThread2 = Task.Factory.StartNew(() => worker(2), TaskCreationOptions.LongRunning); Task workerThread3 = Task.Factory.StartNew(() => worker(2), TaskCreationOptions.LongRunning); Task switcherThread = Task.Factory.StartNew(() => switcher(), TaskCreationOptions.LongRunning); Task.WaitAll(workerThread1, workerThread2, workerThread3, switcherThread); Assert.IsTrue(gate1Executed > 0); Assert.IsTrue(gate2Executed > 0); }