private void PoolRunner(int iterations, ConcurrentRingBufferImpl <Data> pool)
 {
     for (int i = 0; i < iterations; i++)
     {
         Data data = pool.Pop();
         Interlocked.Increment(ref data.Counter);
         pool.Push(data);
     }
 }
        public void SingleThreadAccessTest(int size, bool prefill)
        {
            ConcurrentRingBufferImpl <Data> pool = new ConcurrentRingBufferImpl <Data>(size);

            pool.Initialize(() => new Data(), prefill);

            var distintValues = pool.Data.Distinct(new DataComparer()).Count();

            Assert.Equal(pool.Data.Count, distintValues);
            List <Data> list = new List <Data>(size);

            for (int x = 0; x < size; x++)
            {
                var item = pool.Pop();
                item.Counter += 1;
                list.Add(item);
            }

            Assert.Equal(0, pool.Data.Count);

            for (int x = 0; x < size; x++)
            {
                pool.Push(list[x]);
            }
            foreach (var item in pool.Data)
            {
                item.tracked = false;
            }

            GC.Collect(2, GCCollectionMode.Forced);
            long totalUsage = 0;
            long totalCount = 0;

            foreach (var item in pool.Data)
            {
                if (item.Counter > 0)
                {
                    totalUsage += 1;
                }
                totalCount += item.Counter;
            }

            Console.WriteLine("Counter:" + totalCount);
            Console.WriteLine("Usage:" + totalUsage);
            Console.WriteLine("Thrown away:" + Data.destroyed);



            distintValues = pool.Data.Distinct(new DataComparer()).Count();
            Assert.True(pool.Data.Count <= distintValues);
            Assert.True(size <= pool.Data.Count);
        }
        public void ShouldNotBeAbleToPopFromAnEmptyBuffer(int size)
        {
            var    evt = new ManualResetEvent(false);
            Thread t   = new Thread(() =>
            {
                var buffer = new ConcurrentRingBufferImpl <Data>(size);
                buffer.Initialize(() => new Data(), false);
                var data = buffer.Pop();
                Assert.NotNull(data);
            });

            t.Start();

            if (evt.WaitOne(100))
            {
                Assert.False(true, "Thread managed to pop from an empty buffer");
            }
        }
        public void TestSimplePopPush()
        {
            var pool1 = new ConcurrentRingBufferImpl <Data>(4);
            var pool2 = new ConcurrentRingBufferImpl <Data>(4);

            pool1.Initialize(() => new Data(), true);
            pool2.Initialize(() => new Data(), true);


            var quitEvent = new ManualResetEvent(false);


            var t1 = new Thread(() =>
            {
                do
                {
                    var item = pool1.Pop();
                    Thread.Sleep(TimeSpan.FromTicks(new Random(Thread.CurrentThread.ManagedThreadId).Next(5)));
                    pool2.Push(item);
                }while (!quitEvent.WaitOne(1, true));
            });

            var t2 = new Thread(() =>
            {
                do
                {
                    var item = pool2.Pop();
                    Thread.Sleep(TimeSpan.FromTicks(new Random(Thread.CurrentThread.ManagedThreadId).Next(5)));
                    pool1.Push(item);
                }while (!quitEvent.WaitOne(1, true));
            });

            t1.Start();
            t2.Start();
            Thread.Sleep(50);
            quitEvent.Set();
            t1.Join();
            t2.Join();
            GC.Collect(2, GCCollectionMode.Forced);
            Console.WriteLine("Created:{0}", Data.numberCreated);
            Console.WriteLine("Thrown away:{0}", Data.destroyed);
        }
        public void ShouldBeAbleToEmptyBufferCompletely(int size)
        {
            var buffer = new ConcurrentRingBufferImpl <Data>(size);

            buffer.Initialize(() => new Data(), false);

            List <Data> list = new List <Data>();

            for (int x = 0; x < size; x++)
            {
                var data = new Data();

                list.Add(data);
                buffer.Push(data);
            }

            for (int x = 0; x < size; x++)
            {
                Assert.True(list.Contains(buffer.Pop()));
            }
        }
        public void MultiThreadedAccess(int size, bool prefill, int threadCount, int sleep)
        {
            ConcurrentRingBufferImpl <Data> pool = new ConcurrentRingBufferImpl <Data>(size);

            pool.Initialize(() => new Data(), prefill);
            var distintValues = pool.Data.Distinct(new DataComparer()).Count();

            Assert.Equal(pool.Data.Count, distintValues);

            int              localCount = Math.Max(1, size / threadCount);
            List <Thread>    threads    = new List <Thread>();
            ManualResetEvent startEvent = new ManualResetEvent(false);
            StringBuilder    sb         = new StringBuilder();

            Console.WriteLine("Testing with:{0} items per thread", localCount);
            for (int y = 0; y < threadCount; y++)
            {
                var thread = new Thread(() =>
                {
                    var random = new Random(Thread.CurrentThread.ManagedThreadId);
                    try
                    {
                        startEvent.WaitOne();

                        Thread.Sleep(TimeSpan.FromTicks(random.Next(5)));
                        Stack <Data> list = new Stack <Data>(localCount);
                        for (int x = 0; x < localCount; x++)
                        {
                            var item = pool.Pop();
                            item.SetOwner();
                            Thread.Sleep(TimeSpan.FromMilliseconds(random.Next(2) * sleep));

                            item.Counter += 1;
                            list.Push(item);
                        }

                        // Assert that we got at least as many as we requested
                        Assert.Equal(localCount, list.Count);

                        for (int x = localCount - 1; x > -1; x--)
                        {
                            var item = list.Pop();
                            Thread.Sleep(TimeSpan.FromMilliseconds(random.Next(1)));
                            item.ReleaseOwner();
                            pool.Push(item);
                        }
                    }
                    catch (Exception e)
                    {
                        lock (sb)
                        {
                            sb.Append(e);
                        }
                    }
                });

                threads.Add(thread);
            }
            threads.ForEach(t => t.Start());
            startEvent.Set();
            Parallel.ForEach(threads, t => t.Join(TimeSpan.FromSeconds(10)));

            if (sb.Length > 0)
            {
                Assert.True(false, sb.ToString());
            }
            foreach (var item in pool.Data)
            {
                item.tracked = false;
            }
            GC.Collect(2, GCCollectionMode.Forced);
            long totalUsage = 0;
            long totalCount = 0;

            foreach (var item in pool.Data)
            {
                if (item.Counter > 0)
                {
                    totalUsage += 1;
                }
                totalCount += item.Counter;
            }

            Console.WriteLine("Counter:" + totalCount);
            Console.WriteLine("Usage:" + totalUsage);
            Console.WriteLine("Thrown away:" + Data.destroyed);
            Console.WriteLine("Thrown away (pool):" + pool.ThrownAwayObjects);
            Console.WriteLine("Created (pool):" + pool.Created);



            distintValues = pool.Data.Distinct(new DataComparer()).Count();
            Assert.True(pool.Data.Count <= distintValues);

            if (prefill)
            {
                // We cant know how many objects are created when we dont prefill pools
                if (threadCount <= size)
                {
                    Assert.Equal(size, pool.ObjectsInPool);
                }
            }
        }