Пример #1
0
        public void TestMoveFromLocalQueueToGlobal()
        {
            ThreadPoolQueueController q     = new ThreadPoolQueueController(100, 50);
            ThreadPoolLocalQueue      local = new ThreadPoolLocalQueue();

            for (int i = 0; i < 100; i++)
            {
                q.Add(new TestThreadPoolItem(i), null);
            }

            Assert.AreEqual(100, q.GlobalQueue.OccupiedNodesCount);
            Assert.AreEqual(0, q.GlobalQueue.FreeNodesCount);

            for (int i = 100; i < 110; i++)
            {
                Assert.IsTrue(local.TryAddLocal(new TestThreadPoolItem(i)));
            }

            q.MoveItemsFromLocalQueueToGlobal(local);
            Assert.AreEqual(0, q.GlobalQueue.FreeNodesCount);
            Assert.AreEqual(110, q.GlobalQueue.OccupiedNodesCount);
            Assert.AreEqual(110, q.GlobalQueue.ExtendedCapacity);

            for (int i = 0; i < 110; i++)
            {
                Assert2.AreEqual(i, q.Take(null));
            }

            Assert.AreEqual(100, q.GlobalQueue.FreeNodesCount);
            Assert.AreEqual(0, q.GlobalQueue.OccupiedNodesCount);
            Assert.AreEqual(100, q.GlobalQueue.ExtendedCapacity);
        }
Пример #2
0
        public void TestLocalThreadQueuePrimaryScenario()
        {
            ThreadPoolLocalQueue q = new ThreadPoolLocalQueue();

            RunLocalThreadQueuePrimaryScenario(q, int.MaxValue / 400 + 13, Environment.ProcessorCount, 32);
            RunLocalThreadQueuePrimaryScenario(q, int.MaxValue / 400 + 13, Environment.ProcessorCount, 32);
        }
Пример #3
0
        //[TestMethod]
        //[Timeout(30 * 60 * 1000)]
        //[Ignore]
        public void TestLocalThreadQueuePrimaryScenarioManyRun()
        {
            ThreadPoolLocalQueue q = new ThreadPoolLocalQueue();

            for (int i = 0; i < 200; i++)
            {
                RunLocalThreadQueuePrimaryScenario(q, int.MaxValue / 40 + 13, (i % Environment.ProcessorCount) + 1, 32);
            }
        }
Пример #4
0
        //[TestMethod]
        //[Timeout(20 * 60 * 1000)]
        //[Ignore]
        public void TestAddStealManyElementsManyRun()
        {
            ThreadPoolLocalQueue q = new ThreadPoolLocalQueue();

            for (int i = 0; i < 100; i++)
            {
                RunLocalThreadQueueAddStealTest(q, int.MaxValue / 20 + 13, 32);
            }
        }
Пример #5
0
        public void TestSingleAddSteal()
        {
            ThreadPoolLocalQueue q = new ThreadPoolLocalQueue();

            Assert.IsTrue(q.TryAddLocal(new TestThreadPoolItem(1)));
            ThreadPoolWorkItem item = null;

            Assert.IsTrue(q.TrySteal(out item));
            Assert.IsNotNull(item);
            Assert2.AreEqual(1, item);
        }
Пример #6
0
        public void TestStealingWakeUp()
        {
            ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[]
            {
                new ThreadPoolLocalQueue(),
                new ThreadPoolLocalQueue(),
                new ThreadPoolLocalQueue(),
                new ThreadPoolLocalQueue(),
            };

            ThreadPoolQueueController q = new ThreadPoolQueueController(100, 50);

            for (int i = 0; i < locQ.Length; i++)
            {
                q.AddLocalQueue(locQ[i]);
            }

            bool       takeCompleted = false;
            List <int> takenItems    = new List <int>();

            Task.Run(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    takenItems.Add((TestThreadPoolItem)q.Take(locQ[0]));
                }
                takeCompleted = true;
            });

            Thread.Sleep(1000);
            Assert.IsFalse(takeCompleted);


            for (int i = 0; i < 100; i++)
            {
                locQ[1 + (i % (locQ.Length - 1))].TryAddLocal(new TestThreadPoolItem(i));
                Thread.Sleep(100);
            }

            Thread.Sleep(1000);
            Assert.IsTrue(takeCompleted);

            Assert.AreEqual(100, takenItems.Count);
            takenItems.Sort();

            for (int i = 0; i < 100; i++)
            {
                Assert.AreEqual(i, takenItems[i]);
            }
        }
Пример #7
0
        private void RunLocalThreadQueueAddStealTest(ThreadPoolLocalQueue q, int elemCount, int fillFactor)
        {
            Random rnd      = new Random();
            int    addElem  = 0;
            int    takeElem = 0;

            List <int> takenIndexes = new List <int>(elemCount + 1);

            while (takeElem < elemCount)
            {
                int addCount = rnd.Next(fillFactor);
                for (int i = 0; i < addCount; i++)
                {
                    if (addElem >= elemCount || !q.TryAddLocal(new TestThreadPoolItem(addElem)))
                    {
                        break;
                    }
                    addElem++;
                }

                int removeCount = rnd.Next(fillFactor);
                for (int i = 0; i < removeCount; i++)
                {
                    ThreadPoolWorkItem tmp = null;
                    if (!q.TrySteal(out tmp))
                    {
                        break;
                    }

                    Assert.IsNotNull(tmp);
                    takenIndexes.Add((TestThreadPoolItem)tmp);
                    takeElem++;
                }
            }

            Assert.AreEqual(elemCount, takenIndexes.Count);

            takenIndexes.Sort();

            for (int i = 0; i < elemCount; i++)
            {
                Assert.AreEqual(i, takenIndexes[i]);
            }
        }
Пример #8
0
        public void TestItemStealingWork()
        {
            ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[]
            {
                new ThreadPoolLocalQueue(),
                new ThreadPoolLocalQueue(),
                new ThreadPoolLocalQueue(),
                new ThreadPoolLocalQueue(),
            };

            ThreadPoolQueueController q = new ThreadPoolQueueController(100, 1000);

            for (int i = 0; i < locQ.Length; i++)
            {
                q.AddLocalQueue(locQ[i]);
            }

            locQ[0].TryAddLocal(new TestThreadPoolItem(0));
            locQ[1].TryAddLocal(new TestThreadPoolItem(1));
            locQ[2].TryAddLocal(new TestThreadPoolItem(2));
            locQ[3].TryAddLocal(new TestThreadPoolItem(3));

            List <int> extractedItems = new List <int>();

            for (int i = 0; i < 4; i++)
            {
                ThreadPoolWorkItem item = null;
                Assert.IsTrue(q.TryTake(locQ[0], out item, 0, CancellationToken.None, true));
                extractedItems.Add((TestThreadPoolItem)item);
            }

            ThreadPoolWorkItem tmp = null;

            Assert.IsFalse(q.TryTake(locQ[0], out tmp, 0, CancellationToken.None, true));

            extractedItems.Sort();
            Assert.AreEqual(4, extractedItems.Count);
            for (int i = 0; i < extractedItems.Count; i++)
            {
                Assert.AreEqual(i, extractedItems[i]);
            }
        }
Пример #9
0
        public void TestLocalThreadQueueUsage()
        {
            ThreadPoolLocalQueue      local = new ThreadPoolLocalQueue();
            ThreadPoolQueueController q     = new ThreadPoolQueueController(100, 1000);

            q.AddLocalQueue(local);

            q.Add(new TestThreadPoolItem(1), local);

            ThreadPoolWorkItem item = null;

            Assert.IsTrue(local.TryTakeLocal(out item));
            Assert2.AreEqual(1, item);

            local.TryAddLocal(new TestThreadPoolItem(1));

            item = null;
            Assert.IsTrue(q.TryTake(local, out item, 0, CancellationToken.None, true));
            Assert2.AreEqual(1, item);
        }
Пример #10
0
        public void TestAddTakeUpToTheLimit()
        {
            ThreadPoolLocalQueue q = new ThreadPoolLocalQueue();
            int index = 0;

            while (q.TryAddLocal(new TestThreadPoolItem(index)))
            {
                index++;
                Assert.IsTrue(index < int.MaxValue);
            }

            ThreadPoolWorkItem item = null;

            while (q.TryTakeLocal(out item))
            {
                Assert.IsNotNull(item);
                Assert.IsTrue((TestThreadPoolItem)item == --index);
            }

            Assert.AreEqual(0, index);
        }
Пример #11
0
        //private static void TestLocalThreadQueueAsQueue(ILocalThreadQueue q, int elemCount, int fillFactor)
        //{
        //    int trackElemCount = elemCount;

        //    Stopwatch sw = Stopwatch.StartNew();


        //    while (trackElemCount > 0)
        //    {
        //        int initial = trackElemCount;

        //        for (int i = 0; i < fillFactor; i++)
        //        {
        //            if (!q.TryAddGlobal(initial--))
        //                Console.WriteLine("11");
        //        }

        //        initial = trackElemCount;
        //        for (int i = 0; i < fillFactor; i++)
        //        {
        //            object tmp = null;
        //            //q.TryRemove(out tmp);
        //            if (!q.TryRemoveGlobal(out tmp))
        //                Console.WriteLine("22");
        //            if ((int)tmp != initial--)
        //                Console.WriteLine("33");
        //        }
        //        trackElemCount -= fillFactor;
        //    }

        //    sw.Stop();

        //    Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
        //    Console.WriteLine();
        //}


        //private static void TestLocalThreadQueue2AsQueue(ILocalThreadQueue2 q, int elemCount, int fillFactor)
        //{
        //    int trackElemCount = elemCount;

        //    Stopwatch sw = Stopwatch.StartNew();


        //    while (trackElemCount > 0)
        //    {
        //        int initial = trackElemCount;

        //        for (int i = 0; i < fillFactor; i++)
        //        {
        //            if (!q.TryAddLocal(initial--))
        //                Console.WriteLine("11");
        //        }

        //        initial = trackElemCount;
        //        for (int i = 0; i < fillFactor; i++)
        //        {
        //            object tmp = null;
        //            //q.TryRemove(out tmp);
        //            if (!q.TryTakeLocal(out tmp))
        //                Console.WriteLine("22");
        //            if ((int)tmp != initial--)
        //                Console.WriteLine("33");
        //        }
        //        trackElemCount -= fillFactor;
        //    }

        //    sw.Stop();

        //    Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
        //    Console.WriteLine();
        //}


        //private static void TestLocalThreadQueueAsStack(LocalThreadQueue q, int elemCount, int fillFactor)
        //{
        //    int trackElemCount = elemCount;

        //    Stopwatch sw = Stopwatch.StartNew();


        //    while (trackElemCount > 0)
        //    {
        //        int initial = trackElemCount;
        //        for (int i = 0; i < fillFactor; i++)
        //        {
        //            if (!q.TryAddGlobal(initial--))
        //                Console.WriteLine("11");
        //        }

        //        for (int i = 0; i < fillFactor; i++)
        //        {
        //            object tmp = null;
        //            //q.TryRemove(out tmp);
        //            if (!q.TryRemoveGlobal(out tmp))
        //                Console.WriteLine("22");
        //            if ((int)tmp != ++initial)
        //                Console.WriteLine("33");
        //        }
        //        trackElemCount -= fillFactor;
        //    }

        //    sw.Stop();

        //    Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
        //    Console.WriteLine();
        //}


        private static void TestLocalThreadQueue2AsStack(ThreadPoolLocalQueue q, int elemCount, int fillFactor)
        {
            int trackElemCount = elemCount;

            Stopwatch sw = Stopwatch.StartNew();


            while (trackElemCount > 0)
            {
                int initial = trackElemCount;
                for (int i = 0; i < fillFactor; i++)
                {
                    if (!q.TryAddLocal(new TestThreadPoolItem(initial--)))
                    {
                        Console.WriteLine("11");
                    }
                }

                for (int i = 0; i < fillFactor; i++)
                {
                    ThreadPoolWorkItem tmp = null;
                    //q.TryRemove(out tmp);
                    if (!q.TryTakeLocal(out tmp))
                    {
                        Console.WriteLine("22");
                    }
                    if ((TestThreadPoolItem)tmp != ++initial)
                    {
                        Console.WriteLine("33");
                    }
                }
                trackElemCount -= fillFactor;
            }

            sw.Stop();

            Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
            Console.WriteLine();
        }
Пример #12
0
        private void RunLocalThreadQueuePrimaryScenario(ThreadPoolLocalQueue q, int elemCount, int slealThCount, int fillFactor)
        {
            int trackElemCount = elemCount;
            int addFinished    = 0;

            int atomicRandom = 0;

            Thread mainThread = null;

            Thread[] stealThreads = new Thread[slealThCount];

            List <int> global = new List <int>(elemCount + 1);

            Action mainAction = () =>
            {
                List <int> data = new List <int>(elemCount);

                Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount);

                while (Volatile.Read(ref trackElemCount) >= 0)
                {
                    int addCount = fillFactor;
                    if (rnd != null)
                    {
                        addCount = rnd.Next(fillFactor);
                    }

                    for (int i = 0; i < addCount; i++)
                    {
                        int item = --trackElemCount;
                        if (item < 0)
                        {
                            break;
                        }
                        if (!q.TryAddLocal(new TestThreadPoolItem(item)))
                        {
                            ++trackElemCount;
                            break;
                        }
                    }

                    int removeCount = rnd.Next(fillFactor);

                    for (int i = 0; i < removeCount; i++)
                    {
                        ThreadPoolWorkItem item = null;
                        if (!q.TryTakeLocal(out item))
                        {
                            break;
                        }
                        data.Add((TestThreadPoolItem)item);
                    }
                }

                Interlocked.Increment(ref addFinished);

                ThreadPoolWorkItem finalItem = null;
                while (q.TryTakeLocal(out finalItem))
                {
                    data.Add((TestThreadPoolItem)finalItem);
                }

                lock (global)
                    global.AddRange(data);
            };

            Action stealAction = () =>
            {
                Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount);

                List <int> data = new List <int>();

                while (Volatile.Read(ref addFinished) < 1 && Volatile.Read(ref trackElemCount) > elemCount / 1000)
                {
                    ThreadPoolWorkItem tmp;
                    if (q.TrySteal(out tmp))
                    {
                        data.Add((TestThreadPoolItem)tmp);
                    }

                    int sleepTime = rnd.Next(5) - 3;
                    if (sleepTime > 0)
                    {
                        Thread.Sleep(sleepTime);
                    }
                }

                lock (global)
                    global.AddRange(data);
            };


            mainThread = new Thread(new ThreadStart(mainAction));
            for (int i = 0; i < stealThreads.Length; i++)
            {
                stealThreads[i] = new Thread(new ThreadStart(stealAction));
            }


            mainThread.Start();
            for (int i = 0; i < stealThreads.Length; i++)
            {
                stealThreads[i].Start();
            }


            mainThread.Join();
            for (int i = 0; i < stealThreads.Length; i++)
            {
                stealThreads[i].Join();
            }


            Assert.AreEqual(elemCount, global.Count, "Incorrect element count");

            global.Sort();


            for (int i = 0; i < elemCount; i++)
            {
                Assert.AreEqual(i, global[i], "Incorrect data");
            }
        }
Пример #13
0
        public void TestAddStealManyElements()
        {
            ThreadPoolLocalQueue q = new ThreadPoolLocalQueue();

            RunLocalThreadQueueAddStealTest(q, int.MaxValue / 200 + 13, 32);
        }
Пример #14
0
        private void RunComplexTest(ThreadPoolQueueController q, int elemCount, int thCount)
        {
            int mainIndex    = -1;
            int atomicRandom = 0;

            int trackElemCount = elemCount;
            int addFinished    = 0;

            ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[thCount];
            for (int i = 0; i < locQ.Length; i++)
            {
                locQ[i] = new ThreadPoolLocalQueue();
                q.AddLocalQueue(locQ[i]);
            }

            Thread[] threadsMain       = new Thread[thCount];
            Thread[] threadsAdditional = new Thread[thCount];

            CancellationTokenSource tokSrc = new CancellationTokenSource();

            List <int> global = new List <int>(elemCount);

            Action additionalAction = () =>
            {
                Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2);

                while (true)
                {
                    int item = Interlocked.Decrement(ref trackElemCount);
                    if (item < 0)
                    {
                        break;
                    }

                    q.Add(new TestThreadPoolItem(item), null);

                    int sleepTime = rnd.Next(1000);
                    if (sleepTime > 0)
                    {
                        Thread.SpinWait(sleepTime);
                    }

                    if (rnd.Next(100) == 0)
                    {
                        q.ExtendGlobalQueueCapacity(50);
                    }
                }

                Interlocked.Increment(ref addFinished);
            };


            Action mainAction = () =>
            {
                var localQ = locQ[Interlocked.Increment(ref mainIndex)];

                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)
                    {
                        ThreadPoolWorkItem tmp = null;
                        if (q.TryTake(localQ, out tmp, -1, tokSrc.Token, true))
                        {
                            data.Add((TestThreadPoolItem)tmp);
                        }

                        int sleepTime = rnd.Next(500);
                        if (sleepTime > 0)
                        {
                            Thread.SpinWait(sleepTime);
                        }

                        if (rnd.Next(10) == 0)
                        {
                            int item = Interlocked.Decrement(ref trackElemCount);
                            if (item >= 0)
                            {
                                while (!q.TryAdd(new TestThreadPoolItem(item), localQ, false, 0, CancellationToken.None))
                                {
                                    if (q.TryTake(localQ, out tmp, 0, CancellationToken.None, true))
                                    {
                                        data.Add((TestThreadPoolItem)tmp);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (OperationCanceledException) { }

                ThreadPoolWorkItem tmp2;
                while (q.TryTake(localQ, out tmp2, 0, CancellationToken.None, true))
                {
                    data.Add((TestThreadPoolItem)tmp2);
                }

                lock (global)
                    global.AddRange(data);
            };

            Task.Delay(1000).ContinueWith(t => q.ExtendGlobalQueueCapacity(50));


            for (int i = 0; i < threadsMain.Length; i++)
            {
                threadsMain[i] = new Thread(new ThreadStart(mainAction));
            }
            for (int i = 0; i < threadsAdditional.Length; i++)
            {
                threadsAdditional[i] = new Thread(new ThreadStart(additionalAction));
            }


            for (int i = 0; i < threadsMain.Length; i++)
            {
                threadsMain[i].Start();
            }
            for (int i = 0; i < threadsAdditional.Length; i++)
            {
                threadsAdditional[i].Start();
            }


            for (int i = 0; i < threadsAdditional.Length; i++)
            {
                threadsAdditional[i].Join();
            }
            tokSrc.Cancel();
            for (int i = 0; i < threadsMain.Length; i++)
            {
                threadsMain[i].Join();
            }


            Assert.AreEqual(elemCount, global.Count);
            global.Sort();

            for (int i = 0; i < elemCount; i++)
            {
                Assert.AreEqual(i, global[i]);
            }

            for (int i = 0; i < locQ.Length; i++)
            {
                q.RemoveLocalQueue(locQ[i]);
            }
        }
Пример #15
0
        private static bool TestLocalThreadQueuePrimaryScenario(ThreadPoolLocalQueue q, int elemCount, int slealThCount, int fillFactor, bool useRandom)
        {
            int trackElemCount = elemCount;
            int addFinished    = 0;

            int atomicRandom = 0;

            Thread mainThread = null;

            Thread[] stealThreads = new Thread[slealThCount];

            List <int> global = new List <int>(elemCount);

            Action mainAction = () =>
            {
                List <int> data = new List <int>(elemCount);

                Random rnd = null;
                if (useRandom)
                {
                    rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount);
                }

                while (Volatile.Read(ref trackElemCount) >= 0)
                {
                    int addCount = fillFactor;
                    if (rnd != null)
                    {
                        addCount = rnd.Next(fillFactor);
                    }

                    for (int i = 0; i < addCount; i++)
                    {
                        int item = --trackElemCount;
                        if (item < 0)
                        {
                            break;
                        }
                        if (!q.TryAddLocal(new TestThreadPoolItem(item)))
                        {
                            ++trackElemCount;
                            break;
                        }
                    }

                    int removeCount = fillFactor;
                    if (rnd != null)
                    {
                        removeCount = rnd.Next(fillFactor);
                    }

                    for (int i = 0; i < removeCount; i++)
                    {
                        ThreadPoolWorkItem item = null;
                        if (!q.TryTakeLocal(out item))
                        {
                            break;
                        }
                        data.Add((TestThreadPoolItem)item);
                    }
                }

                Interlocked.Increment(ref addFinished);

                ThreadPoolWorkItem finalItem = null;
                while (q.TryTakeLocal(out finalItem))
                {
                    data.Add((TestThreadPoolItem)finalItem);
                }

                lock (global)
                    global.AddRange(data);
            };

            Action stealAction = () =>
            {
                Random rnd = null;
                if (useRandom)
                {
                    rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount);
                }

                List <int> data = new List <int>();

                while (Volatile.Read(ref addFinished) < 1 && Volatile.Read(ref trackElemCount) > elemCount / 1000)
                {
                    ThreadPoolWorkItem tmp;
                    if (q.TrySteal(out tmp))
                    {
                        data.Add((TestThreadPoolItem)tmp);
                    }

                    int sleepTime = Volatile.Read(ref trackElemCount) % 2;
                    if (rnd != null)
                    {
                        sleepTime = rnd.Next(2);
                    }
                    if (sleepTime > 0)
                    {
                        Thread.Sleep(sleepTime);
                    }
                }

                lock (global)
                    global.AddRange(data);
            };


            mainThread = new Thread(new ThreadStart(mainAction));
            for (int i = 0; i < stealThreads.Length; i++)
            {
                stealThreads[i] = new Thread(new ThreadStart(stealAction));
            }

            Stopwatch sw = Stopwatch.StartNew();

            mainThread.Start();
            for (int i = 0; i < stealThreads.Length; i++)
            {
                stealThreads[i].Start();
            }


            mainThread.Join();
            for (int i = 0; i < stealThreads.Length; i++)
            {
                stealThreads[i].Join();
            }


            sw.Stop();

            bool result = true;

            global.Sort();
            if (global.Count != elemCount)
            {
                result = false;
                Console.WriteLine("Incorrect element count");
            }

            HashSet <int> set = new HashSet <int>(global);

            if (set.Count != global.Count)
            {
                result = false;
                Console.WriteLine("Incorrect distinct element count");
            }

            for (int i = 0; i < Math.Min(elemCount, global.Count); i++)
            {
                if (global[i] != i)
                {
                    result = false;
                    Console.WriteLine("Incorrect data");
                    break;
                }
            }


            Console.WriteLine("PrimaryScenario " + q.GetType().Name + ". Element count = " + elemCount.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
            Console.WriteLine();
            return(result);
        }
Пример #16
0
        // ==============


        private static bool RunComplexTestOnThreadPoolQueue(int elemCount, int thCount)
        {
            ThreadPoolQueueController q = new ThreadPoolQueueController(1000, 100);
            int mainIndex = -1;

            int trackElemCount = elemCount;
            int addFinished    = 0;

            ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[thCount];
            for (int i = 0; i < locQ.Length; i++)
            {
                locQ[i] = new ThreadPoolLocalQueue();
                q.AddLocalQueue(locQ[i]);
            }

            Thread[] threadsMain       = new Thread[thCount];
            Thread[] threadsAdditional = new Thread[thCount];

            CancellationTokenSource tokSrc = new CancellationTokenSource();

            List <int> global = new List <int>(elemCount);

            Action additionalAction = () =>
            {
                while (true)
                {
                    int item = Interlocked.Decrement(ref trackElemCount);
                    if (item < 0)
                    {
                        break;
                    }

                    q.Add(new TestThreadPoolItem(item), null);
                }

                Interlocked.Increment(ref addFinished);
            };


            Action mainAction = () =>
            {
                var localQ = locQ[Interlocked.Increment(ref mainIndex)];

                List <int> data = new List <int>();

                try
                {
                    int index = 0;
                    while (Volatile.Read(ref addFinished) < thCount)
                    {
                        ThreadPoolWorkItem tmp = null;
                        if (q.TryTake(localQ, out tmp, -1, tokSrc.Token, true))
                        {
                            data.Add((TestThreadPoolItem)tmp);
                        }

                        if (((index++) % 10) == 0)
                        {
                            int item = Interlocked.Decrement(ref trackElemCount);
                            if (item >= 0)
                            {
                                while (!q.TryAdd(new TestThreadPoolItem(item), localQ, false, 0, CancellationToken.None))
                                {
                                    if (q.TryTake(localQ, out tmp, 0, CancellationToken.None, true))
                                    {
                                        data.Add((TestThreadPoolItem)tmp);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (OperationCanceledException) { }

                ThreadPoolWorkItem tmp2;
                while (q.TryTake(localQ, out tmp2, 0, CancellationToken.None, true))
                {
                    data.Add((TestThreadPoolItem)tmp2);
                }

                lock (global)
                    global.AddRange(data);
            };


            for (int i = 0; i < threadsMain.Length; i++)
            {
                threadsMain[i] = new Thread(new ThreadStart(mainAction));
            }
            for (int i = 0; i < threadsAdditional.Length; i++)
            {
                threadsAdditional[i] = new Thread(new ThreadStart(additionalAction));
            }

            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < threadsMain.Length; i++)
            {
                threadsMain[i].Start();
            }
            for (int i = 0; i < threadsAdditional.Length; i++)
            {
                threadsAdditional[i].Start();
            }


            for (int i = 0; i < threadsAdditional.Length; i++)
            {
                threadsAdditional[i].Join();
            }
            tokSrc.Cancel();
            for (int i = 0; i < threadsMain.Length; i++)
            {
                threadsMain[i].Join();
            }

            sw.Stop();

            bool result = true;

            if (elemCount != global.Count)
            {
                Console.WriteLine("Incorrect items count");
                result = false;
            }

            global.Sort();

            for (int i = 0; i < Math.Min(elemCount, global.Count); i++)
            {
                if (global[i] != i)
                {
                    Console.WriteLine("Incorrect items value");
                    result = false;
                    break;
                }
            }

            Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
            Console.WriteLine();
            return(result);
        }