public void TestEnqueueDequeueToTheLimit() { const int batchSize = 13; BlockingBatchingQueue <int> col = new BlockingBatchingQueue <int>(batchSize: batchSize, boundedCapacityInBatches: 2); for (int i = 0; i < batchSize * col.BoundedCapacityInBatches; i++) { Assert.IsTrue(col.TryAdd(i)); } Assert.IsFalse(col.TryAdd(int.MaxValue)); List <int> takenItems = new List <int>(); for (int i = 0; i < col.BoundedCapacityInBatches; i++) { Assert.IsTrue(col.TryTake(out int[] batch)); takenItems.AddRange(batch); } Assert.IsFalse(col.TryTake(out _)); for (int i = 0; i < takenItems.Count; i++) { Assert.AreEqual(i, takenItems[i]); } }
public void TestCompleteCurrentBatch() { const int batchSize = 10; BlockingBatchingQueue <int> col = new BlockingBatchingQueue <int>(batchSize: batchSize); Assert.AreEqual(0, col.Count); Assert.AreEqual(0, col.CompletedBatchCount); Assert.IsFalse(col.CompleteCurrentBatch()); Assert.AreEqual(0, col.Count); Assert.AreEqual(0, col.CompletedBatchCount); int[] dequeuedItems = null; Assert.IsFalse(col.TryTake(out dequeuedItems)); col.Add(0); col.Add(1); Assert.AreEqual(2, col.Count); Assert.AreEqual(0, col.CompletedBatchCount); Assert.IsTrue(col.CompleteCurrentBatch()); Assert.AreEqual(2, col.Count); Assert.AreEqual(1, col.CompletedBatchCount); Assert.IsTrue(col.TryTake(out dequeuedItems)); Assert.AreEqual(2, dequeuedItems.Length); for (int i = 0; i < dequeuedItems.Length; i++) { Assert.AreEqual(i, dequeuedItems[i]); } Assert.AreEqual(0, col.Count); Assert.AreEqual(0, col.CompletedBatchCount); }
public void TestTimeoutWorks() { const int batchSize = 17; BlockingBatchingQueue <int> queue = new BlockingBatchingQueue <int>(batchSize: batchSize, boundedCapacityInBatches: 8); Barrier bar = new Barrier(2); int takeResult = 0; int addResult = 0; Task task = Task.Run(() => { bar.SignalAndWait(); int[] item = null; if (queue.TryTake(out item, 100)) { Interlocked.Exchange(ref takeResult, 1); } else { Interlocked.Exchange(ref takeResult, 2); } while (queue.TryAdd(-1)) { ; } if (queue.TryAdd(100, 100)) { Interlocked.Exchange(ref addResult, 1); } else { Interlocked.Exchange(ref addResult, 2); } }); bar.SignalAndWait(); TimingAssert.AreEqual(10000, 2, () => Volatile.Read(ref takeResult), "take"); TimingAssert.AreEqual(10000, 2, () => Volatile.Read(ref addResult), "Add"); task.Wait(); }
private void RunComplexTest(BlockingBatchingQueue <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 completeBatchThread = 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.Add(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.TryTake(out tmp, -1, tokSrc.Token)) { data.AddRange(tmp); } int sleepTime = rnd.Next(12); if (sleepTime > 0) { SpinWaitHelper.SpinWait(sleepTime); } } } catch (OperationCanceledException) { } int[] tmp2; while (q.TryTake(out tmp2)) { data.AddRange(tmp2); } q.CompleteCurrentBatch(); while (q.TryTake(out tmp2)) { data.AddRange(tmp2); } lock (global) global.AddRange(data); }; Action completeBatchAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); while (Volatile.Read(ref addFinished) < thCount && !tokSrc.IsCancellationRequested) { q.CompleteCurrentBatch(); Thread.Sleep(rnd.Next(2)); } }; 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)); } completeBatchThread = new Thread(new ThreadStart(completeBatchAction)); for (int i = 0; i < threadsTake.Length; i++) { threadsTake[i].Start(); } for (int i = 0; i < threadsAdd.Length; i++) { threadsAdd[i].Start(); } completeBatchThread.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(); } completeBatchThread.Join(); Assert.AreEqual(elemCount, global.Count); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i]); } }
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]); } }