// This is a HUGE test which involves actual threads and takes time, // so technically it is not a unit test. // But this is a sort of pet-form of the whole project, and covers the main sense of it. // Actually, this is a code of my prototype application so it is also not well structured. // // Whats going on: // - "Reader" thread produces a sequence of numbers and passes to Producer-Consumer (P-C) // - A number of worker threads consume and "process" them (actually do nothing with a random delay) // then pass to the next P-C // - A "writer" thread collects all the integers passed in the list. // The goal of the test is to ensure that the final list contains exactly the same numbers // as produced by "reader" public void ProducerConsumerShouldWork() { var readerPc = new ProducerConsumer <IntTask>(8, new ProducerConsumerQueue <IntTask>()); var processorsPcs = new List <ProducerConsumer <IntTask> >(); var finishPc = new ProducerConsumer <IntTask>(8, new ProducerConsumerQueue <IntTask>()); const int integersToReadCount = 50; var integersToRead = new List <int>(integersToReadCount); var rand = new Random(DateTime.Now.Millisecond); for (var i = 0; i < integersToReadCount; i++) { integersToRead.Add(rand.Next(10000)); } var readerThread = new Thread(new ThreadStart(() => { var rnd = new Random(DateTime.Now.Millisecond); var currId = 0; for (int i = 0; i < integersToReadCount; i++) { var pc = new IntTask { Id = i, Data = integersToRead[i] }; readerPc.Push(pc); Thread.Sleep(rnd.Next(10)); currId++; } readerPc.Stop(); var endPc = new IntTask { Id = currId, Data = 0 }; finishPc.Push(endPc); })); readerThread.Start(); for (int i = 0; i < 4; i++) { var processorId = i; var prodCons = new ProducerConsumer <IntTask>(4, new ProducerConsumerOrderedQueue <IntTask>()); processorsPcs.Add(prodCons); var processorThread = new Thread(new ThreadStart(() => { var rnd = new Random(DateTime.Now.Millisecond); var pc = readerPc.Pop(); while (pc != null) { processorsPcs[processorId].Push(pc); pc = readerPc.Pop(); Thread.Sleep(rnd.Next(1000)); } })); processorThread.Start(); } var writerList = new List <int>(integersToReadCount); var writer = new Thread(new ThreadStart(() => { int currId = 0; while (true) { var allProcessorsEmpty = true; for (int i = 0; i < processorsPcs.Count; i++) { var t = processorsPcs[i].Peek(); if (t != null) { allProcessorsEmpty = false; if (t.Id == currId) { t = processorsPcs[i].Pop(); writerList.Add(t.Data); currId++; } } } if (allProcessorsEmpty) { var finishPcData = finishPc.Peek(); if (finishPcData != null && finishPcData.Id == currId) { break; } } } })); writer.Start(); writer.Join(); Assert.IsTrue(integersToRead.SequenceEqual(writerList)); }