// ==================== private void AddTakeUpToTheLimitTest(PersistentDiskQueueSegment <int> segment) { int item = 0; while (segment.TryAdd(item++)) { Assert.AreEqual(item, segment.Count); } item--; Assert.IsTrue(segment.IsFull); Assert.IsFalse(segment.IsCompleted); Assert.AreEqual(item, segment.Count); Assert.AreEqual(segment.Capacity, segment.Count); segment.AddForced(item++); Assert.IsTrue(segment.IsFull); Assert.IsFalse(segment.IsCompleted); Assert.AreEqual(item, segment.Count); Assert.AreEqual(segment.Capacity + 1, segment.Count); for (int i = 0; i < 100; i++) { int peekItem = 0; Assert.IsTrue(segment.TryPeek(out peekItem)); Assert.AreEqual(0, peekItem); } for (int i = 0; i < item; i++) { int takeItem = 0; Assert.IsTrue(segment.TryTake(out takeItem)); Assert.AreEqual(i, takeItem); if (i != item - 1) { Assert.IsFalse(segment.IsCompleted); } else { Assert.IsTrue(segment.IsCompleted); } } Assert.IsTrue(segment.IsFull); Assert.IsTrue(segment.IsCompleted); Assert.AreEqual(0, segment.Count); int tmp = 0; Assert.IsFalse(segment.TryAdd(0)); Assert.IsFalse(segment.TryPeek(out tmp)); Assert.IsFalse(segment.TryTake(out tmp)); }
// ======================= private void AddTakePeekTest(PersistentDiskQueueSegment <int> segment) { Assert.AreEqual(0, segment.Count); Assert.IsFalse(segment.IsFull); Assert.IsFalse(segment.IsCompleted); Assert.IsTrue(segment.TryAdd(10)); Assert.AreEqual(1, segment.Count); int item = 0; Assert.IsTrue(segment.TryPeek(out item)); Assert.AreEqual(10, item); Assert.AreEqual(1, segment.Count); item = 0; Assert.IsTrue(segment.TryTake(out item)); Assert.AreEqual(10, item); Assert.AreEqual(0, segment.Count); for (int i = 0; i <= 10; i++) { if (i % 2 == 0) { segment.AddForced(i); } else { Assert.IsTrue(segment.TryAdd(i)); } Assert.AreEqual(i + 1, segment.Count); } for (int i = 0; i <= 10; i++) { item = 0; Assert.IsTrue(segment.TryPeek(out item)); Assert.AreEqual(i, item); item = 0; Assert.IsTrue(segment.TryTake(out item)); Assert.AreEqual(i, item); } Assert.AreEqual(0, segment.Count); }
// ========================= 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 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]}"); } } }