public void Test_CanCompleteAdding(int capacity) { using (StandardTaskBuffer buffer = new StandardTaskBuffer(capacity)) { int actualItemNumber = ProduceItemNumber(capacity); for (int i = 0; i < actualItemNumber; i++) { Assert.IsTrue(buffer.TryAddNewTask(new MockQueuedTaskToken(Guid.NewGuid()))); } //Complete adding buffer.CompleteAdding(); if (buffer.Count > 0) { Assert.IsFalse(buffer.IsCompleted); } else { Assert.IsTrue(buffer.IsCompleted); } //We can no longer add items Assert.IsFalse(buffer.TryAddNewTask(new MockQueuedTaskToken(Guid.NewGuid()))); //We must be able to retrieve the other items for (int i = 0; i < actualItemNumber; i++) { Assert.NotNull(buffer.TryGetNextTask()); } //Now it must be marked as completed Assert.IsTrue(buffer.IsCompleted); } }
public void Test_ConsumerProducerScenario(int nProducers, int nConsumers) { Task coordinator; Task[] allProducers = new Task[nProducers]; Task[] allConsumers = new Task[nConsumers]; int expectedTotal = 0; ConcurrentBag <IQueuedTaskToken> processedTasks = new ConcurrentBag <IQueuedTaskToken>(); using (StandardTaskBuffer buffer = new StandardTaskBuffer(10)) { for (int iProducer = 0; iProducer < nProducers; iProducer++) { allProducers[iProducer] = Task.Run(() => { //Generate a number of items to produce // and add that to the expected total int nItems = new Random().Next(1, 100); Interlocked.Add(ref expectedTotal, nItems); while (nItems > 0) { bool isAdded = buffer.TryAddNewTask(new MockQueuedTaskToken(Guid.NewGuid())); if (isAdded) { nItems--; } else { Task.Delay(10).Wait(); } } }); } for (int iConsumer = 0; iConsumer < nConsumers; iConsumer++) { allConsumers[iConsumer] = Task.Run(() => { //Consumers run until the buffer is completed: // - marked as completed with respect to additons // AND // - has no more items while (!buffer.IsCompleted) { IQueuedTaskToken queuedTaskToken = buffer.TryGetNextTask(); if (queuedTaskToken != null) { processedTasks.Add(queuedTaskToken); } else { Task.Delay(10).Wait(); } } }); } coordinator = Task.Run(() => { //The coordinator waits for all producers // to finish and then marks buffer // addition operations as being completed Task.WaitAll(allProducers); buffer.CompleteAdding(); }); //Wait for all threads to stop Task.WaitAll(coordinator); Task.WaitAll(allConsumers); //Check that: // a) we have the exact number of items we added // b) there are no items that have been processed two times Assert.AreEqual(expectedTotal, processedTasks.Count); foreach (IQueuedTaskToken queuedTaskToken in processedTasks) { Assert.AreEqual(1, processedTasks.Count(t => t.DequeuedTask.Id == queuedTaskToken.DequeuedTask.Id)); } } }