private ConcurrentLinkedList <BOX <int> > AddCheckEntries(bool bTail = true, int countEntries = 10)
        {
            var LL = new ConcurrentLinkedList <BOX <int> >();
            var n  = new List <int>(Enumerable.Range(0, countEntries));

            foreach (var i in n)
            {
                if (bTail)
                {
                    LL.AddTail(new BOX <int>(i));
                }
                else
                {
                    LL.AddHead(new BOX <int>(i));
                }
            }


            var nFound = 0;
            var node   = LL.Head;

            do
            {
                Assert.AreNotEqual(node.Value, null);
                Assert.AreEqual(true, n.Contains(node.Value.VALUE));
                nFound++;
            }while ((node = node.Next) != null);

            Trace.WriteLine(string.Format("Total Entries {0}", LL.Count), "info");
            Assert.AreEqual(nFound, n.Count);

            return(LL);
        }
        public void AddAtTailCheckCount()
        {
            var LL = new ConcurrentLinkedList <BOX <int> >();
            var n  = Enumerable.Range(0, 100);

            foreach (var i in n)
            {
                LL.AddTail(new BOX <int>(i));
            }

            Trace.WriteLine(string.Format("Total Entries{0}", LL.Count), "info");
            Assert.AreEqual(LL.Count, n.Count());
        }
        private ConcurrentLinkedList <BOX <long> > CreateProducersConsumers(int countEntries,
                                                                            int TailProducers,
                                                                            int TailConsumers,
                                                                            int HeadProducers,
                                                                            int HeadConsumers,
                                                                            int MaxProducerRandomDelay,
                                                                            int MaxConsumersRandomDelay,
                                                                            int InitialConsumerDelay = 10)
        {
            var currentEntry  = 0;
            var totalProduced = 0;
            var totalConsumed = 0;
            var LL            = new ConcurrentLinkedList <BOX <long> >();
            var rnd           = new Random();

            List <Task <int> > consumerTasks = new List <Task <int> >();
            List <Task <int> > producerTasks = new List <Task <int> >();


            Func <bool, string, Task <int> > producer = async(bIsTail, producerId) =>
            {
                var produced = 0;
                Trace.WriteLine(string.Format("Producer {0} is {1}", producerId, bIsTail ? "Tail" : "Head"));


                while (Interlocked.Increment(ref currentEntry) <= countEntries)
                {
                    produced++;
                    var newVal = DateTime.UtcNow.Ticks;
                    Trace.WriteLine(string.Format("Producer {0} + {1}", producerId, newVal));

                    if (bIsTail)
                    {
                        LL.AddTail(new BOX <long>(newVal));
                    }
                    else
                    {
                        LL.AddHead(new BOX <long>(newVal));
                    }


                    await Task.Delay(rnd.Next(0, MaxProducerRandomDelay));
                }
                return(produced);
            };


            Func <bool, string, Task <int> > consumer = async(bIsTail, consumerId) =>
            {
                // all consumer wait a bit this almost elminate the need for that CX below
                await Task.Delay(InitialConsumerDelay); //

                Trace.WriteLine(string.Format("Consumer {0} is {1}", consumerId, bIsTail ?  "Tail" : "Head"));
                var        consumed = 0;
                BOX <long> node;
                while ((bIsTail && null != (node = LL.RemoveTail())) || (!bIsTail && null != (node = LL.RemoveHead())))
                {
                    Assert.AreNotEqual(null, node.VALUE);
                    Trace.WriteLine(string.Format("Consumer {0} - {1}", consumerId, node.VALUE));
                    consumed++;
                    await Task.Delay(rnd.Next(0, MaxConsumersRandomDelay));
                }

                Trace.WriteLine(string.Format("Consumer {0} is {1} -- Exited", consumerId, bIsTail ? "Tail" : "Head"));
                return(consumed);
            };


            // give a head start for consumers.
            for (int p = 1; p <= TailProducers + HeadProducers; p++)
            {
                //avoid hoisted variables.
                var isTail       = (TailProducers > 0 && p <= TailProducers);
                var producerName = string.Concat("P", p);
                producerTasks.Add(Task.Run(
                                      async() => await producer(isTail, producerName))
                                  );
            }

            for (int c = 1; c <= TailConsumers + HeadConsumers; c++)
            {
                var isTail       = (TailConsumers > 0 && c <= TailConsumers);
                var consumerName = string.Concat("C", c);
                consumerTasks.Add(Task.Run(
                                      async() => await consumer(isTail, consumerName))
                                  );
            }


            Task.WhenAll(producerTasks).Wait();
            Task.WhenAll(consumerTasks).Wait();



            // if after all said and done we still have items consume them.
            if (LL.Count > 0)
            {
                Trace.WriteLine("Consumers exited before producers completed work, creating a CX", "warnings");
                totalConsumed += Task <int> .Run(async() => await consumer(true, "CX")).Result;
            }

            // calculate all produced and consumed

            foreach (var p in producerTasks)
            {
                totalProduced += p.Result;
            }

            foreach (var c in consumerTasks)
            {
                totalConsumed += c.Result;
            }

            // are we clean?
            Trace.WriteLine(string.Format("completed produced:{0} consumed:{1}", totalProduced, totalConsumed), "info");
            Assert.AreEqual(totalProduced, totalConsumed);
            return(LL);
        }