public void WaitUntilStopWorkCorrect()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, -1, "name"))
            {
                Assert.AreEqual(-1, testInst.QueueCapacity);

                int expectedWork = 100;
                int executedWork = 0;

                for (int i = 0; i < expectedWork; i++)
                {
                    testInst.Run(() =>
                    {
                        Thread.Sleep(200);
                        Interlocked.Increment(ref executedWork);
                    });
                }

                testInst.Dispose(false, true, false);
                Assert.IsTrue(executedWork < expectedWork);
                Assert.IsTrue(testInst.State == ThreadPoolState.StopRequested);

                testInst.WaitUntilStop();
                Assert.IsTrue(testInst.State == ThreadPoolState.Stopped);
                Assert.AreEqual(expectedWork, executedWork);
            }
        }
        private void ProcessParts(BlockingQueue <byte[]> inputBlockingQueue,
                                  BlockingQueue <BlockingWorkItem <byte[]> > outputBlockingQueue,
                                  Cancellation cancellation = null)
        {
            var threadPool = new StaticThreadPool();

            new Thread(() =>
            {
                while (inputBlockingQueue.Dequeue(out var item))
                {
                    if (cancellation?.IsCancelled() ?? false)
                    {
                        break;
                    }

                    var blockingWorkItem = new BlockingWorkItem <byte[]>();
                    outputBlockingQueue.Enqueue(blockingWorkItem);

                    var part = item;
                    threadPool.QueueJob(() =>
                    {
                        var processed = ProcessPart(part);
                        blockingWorkItem.SetResult(processed);
                    });
                }
                outputBlockingQueue.Complete();
            }).Start();
        }
        public void TestQueueCapacityBound()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, 10, "name"))
            {
                Assert.AreEqual(10, testInst.QueueCapacity);

                int tryRunWorkItem = 100 * testInst.QueueCapacity;
                int runWorkCount   = 0;
                int executedWork   = 0;

                for (int i = 0; i < tryRunWorkItem; i++)
                {
                    if (testInst.TryRun(() =>
                    {
                        Thread.Sleep(500);
                        Interlocked.Increment(ref executedWork);
                    }))
                    {
                        runWorkCount++;
                    }
                }

                testInst.Dispose(true, true, true);
                Assert.IsTrue(runWorkCount > 0);
                Assert.IsTrue(runWorkCount < tryRunWorkItem);
                Assert.AreEqual(runWorkCount, executedWork);
            }
        }
        public void TestLongProcessWork()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, 100, "name"))
            {
                Assert.AreEqual(Environment.ProcessorCount, testInst.ThreadCount);
                Assert.AreEqual(100, testInst.QueueCapacity);

                int expectedWork = 100;
                int executedWork = 0;

                for (int i = 0; i < expectedWork; i++)
                {
                    testInst.Run(() =>
                    {
                        Thread.Sleep(300);
                        Interlocked.Increment(ref executedWork);
                    });
                }

                testInst.Dispose(true, true, true);

                Assert.AreEqual(0, testInst.ThreadCount);
                Assert.IsFalse(testInst.IsWork);
                Assert.AreEqual(expectedWork, executedWork);
            }
        }
        public void TestQueueCapacityBoundExtends()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, 10, "name"))
            {
                int expectedWork = 25;
                int executedWork = 0;

                ManualResetEventSlim tracker = new ManualResetEventSlim();

                for (int i = 0; i < expectedWork; i++)
                {
                    testInst.Run(() =>
                    {
                        tracker.Wait();
                        Interlocked.Increment(ref executedWork);
                    });
                }

                tracker.Set();


                testInst.Dispose(true, true, true);
                Assert.AreEqual(expectedWork, executedWork);
            }
        }
        public void TestTaskSchedulerWork()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(4, -1, "name", false, new StaticThreadPoolOptions()
            {
                UseOwnTaskScheduler = true, UseOwnSyncContext = true
            }))
            {
                bool firstTaskInPool  = false;
                bool secondTaskInPool = false;

                var task = testInst.RunAsTask(() =>
                {
                    firstTaskInPool = testInst.IsThreadPoolThread;
                }).ContinueWith(t =>
                {
                    secondTaskInPool = testInst.IsThreadPoolThread;
                }, testInst.TaskScheduler);

                task.Wait();
                Assert.IsTrue(firstTaskInPool);
                Assert.IsTrue(secondTaskInPool);

                testInst.Dispose();
            }
        }
        private async Task TestAsyncOperationSwitchToPoolInner(StaticThreadPool testInst)
        {
            Assert.IsFalse(testInst.IsThreadPoolThread);

            System.IO.StreamWriter writer = null;
            string fileName = Guid.NewGuid().ToString().Replace('-', '_');

            try
            {
                writer = new System.IO.StreamWriter(new System.IO.FileStream(fileName, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite, 128, true));

                await testInst.SwitchToPool();

                Assert.IsTrue(testInst.IsThreadPoolThread);

                string longString = "test test test test test test test test test test test test";
                for (int i = 0; i < 10; i++)
                {
                    longString += longString;
                }

                await writer.WriteLineAsync(longString);

                Assert.IsTrue(testInst.IsThreadPoolThread);
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }

                System.IO.File.Delete(fileName);
            }
        }
 public void TestSwitchToPoolWork()
 {
     using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, -1, "name"))
     {
         var task = TestSwitchToPoolWorkInner(testInst);
         task.Wait();
         Assert.IsFalse(task.IsFaulted);
     }
 }
 public void RunComplexTest()
 {
     using (StaticThreadPool testInst = new StaticThreadPool(2 * Environment.ProcessorCount, 1000, "name"))
     {
         RunTestOnPool(testInst, 4000000, 120, 2, 4, false);
         RunTestOnPool(testInst, 4000000, 4, 2, 120, false);
         RunTestOnPool(testInst, 4000000, 0, 2, 0, true);
         RunTestOnPool(testInst, 4000000, 0, Environment.ProcessorCount, 0, false);
     }
 }
        private async Task TestSwitchToPoolWorkInner(StaticThreadPool testInst)
        {
            Assert.IsFalse(testInst.IsThreadPoolThread);
            //Assert.IsNull(SynchronizationContext.Current);

            await testInst.SwitchToPool();

            Assert.IsTrue(testInst.IsThreadPoolThread);
            //Assert.IsNotNull(SynchronizationContext.Current);
        }
 public void TestAsyncOperationSwitchToPoolWithTaskScheduller()
 {
     using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, -1, "name", false,
                                                             new StaticThreadPoolOptions()
     {
         UseOwnSyncContext = false, UseOwnTaskScheduler = true
     }))
     {
         var task = TestAsyncOperationSwitchToPoolInner(testInst);
         task.Wait();
         Assert.IsFalse(task.IsFaulted);
     }
 }
        public void TestCantAddAfterCompleteAdding()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, -1, "name"))
            {
                Assert.IsTrue(testInst.TryRun(() => { }));

                testInst.CompleteAdding();

                Assert.IsFalse(testInst.TryRun(() => { }));

                testInst.Run(() => { });
            }
        }
        public void TestTryRunWork()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(Environment.ProcessorCount, 100, "name"))
            {
                int  wasExecuted = 0;
                bool wasRunned   = testInst.TryRun(() =>
                {
                    Interlocked.Exchange(ref wasExecuted, 1);
                });

                Assert.IsTrue(wasRunned);
                TimingAssert.AreEqual(5000, 1, () => Volatile.Read(ref wasExecuted));
            }
        }
        public void TestRunAsTaskWork()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(4, -1, "name", false, new StaticThreadPoolOptions()
            {
                UseOwnTaskScheduler = true, UseOwnSyncContext = true
            }))
            {
                int wasExecuted = 0;

                var task = testInst.RunAsTask(() =>
                {
                    Interlocked.Exchange(ref wasExecuted, 1);
                });

                task.Wait();
                Assert.AreEqual(1, Volatile.Read(ref wasExecuted));
            }
        }
        public void StaticThreadPoolChangeThreadCount()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(0, -1, "name"))
            {
                int expectedWork = 100;
                int executedWork = 0;

                for (int i = 0; i < expectedWork; i++)
                {
                    if (i == 30)
                    {
                        testInst.AddThreads(10);
                    }
                    else if (i == 50)
                    {
                        testInst.RemoveThreads(5);
                    }
                    else if (i == 80)
                    {
                        testInst.SetThreadCount(2);
                    }

                    testInst.Run(() =>
                    {
                        Thread.Sleep(200);
                        Interlocked.Increment(ref executedWork);
                    });

                    Thread.Sleep(10);
                }

                SpinWait.SpinUntil(() => executedWork == expectedWork);

                Assert.AreEqual(2, testInst.ThreadCount);

                testInst.Dispose(true, true, true);

                Assert.AreEqual(0, testInst.ThreadCount);
                Assert.IsFalse(testInst.IsWork);
                Assert.AreEqual(expectedWork, executedWork);
            }
        }
        public void TestRunAsTaskWithParamNoTaskSchedWork()
        {
            using (StaticThreadPool testInst = new StaticThreadPool(4, -1, "name", false, new StaticThreadPoolOptions()
            {
                UseOwnTaskScheduler = false, UseOwnSyncContext = false
            }))
            {
                int wasExecuted = 0;
                int paramValue  = 0;

                var task = testInst.RunAsTask((p) =>
                {
                    Interlocked.Exchange(ref paramValue, p);
                    Interlocked.Exchange(ref wasExecuted, 1);
                }, 100);

                task.Wait();
                Assert.AreEqual(1, Volatile.Read(ref wasExecuted));
                Assert.AreEqual(100, Volatile.Read(ref paramValue));
            }
        }
        private void RunTestOnPool(StaticThreadPool pool, int totalTaskCount, int taskSpinCount, int spawnThreadCount, int spawnSpinTime, bool spawnFromPool)
        {
            Random rndGenerator = new Random();

            int executedTaskCounter = 0;
            int completedTaskCount  = 0;


            Action taskAction = null;

            taskAction = () =>
            {
                int curTaskSpinCount = taskSpinCount;
                lock (rndGenerator)
                    curTaskSpinCount = rndGenerator.Next(taskSpinCount);

                SpinWaitHelper.SpinWait(curTaskSpinCount);

                if (spawnFromPool)
                {
                    if (Interlocked.Increment(ref executedTaskCounter) <= totalTaskCount)
                    {
                        pool.Run(taskAction);
                    }
                }

                Interlocked.Increment(ref completedTaskCount);
            };

            Barrier bar = new Barrier(spawnThreadCount + 1);

            Random spawnRndGenerator = new Random();

            Thread[]    spawnThreads = new Thread[spawnThreadCount];
            ThreadStart spawnAction  = () =>
            {
                bar.SignalAndWait();
                while (Interlocked.Increment(ref executedTaskCounter) <= totalTaskCount)
                {
                    pool.Run(taskAction);

                    int curSpawnSpinCount = spawnSpinTime;
                    lock (spawnRndGenerator)
                        curSpawnSpinCount = spawnRndGenerator.Next(spawnSpinTime);

                    SpinWaitHelper.SpinWait(curSpawnSpinCount);
                }
            };


            for (int i = 0; i < spawnThreads.Length; i++)
            {
                spawnThreads[i] = new Thread(spawnAction);
            }

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

            bar.SignalAndWait();

            TimingAssert.AreEqual(60 * 1000, totalTaskCount, () => Volatile.Read(ref completedTaskCount));
        }