/// <summary>
        /// Деактивирует поток
        /// </summary>
        /// <param name="threadCountLowLimit">Минимальное число активных потоков</param>
        /// <returns>Успешность</returns>
        private bool DeactivateThread(int threadCountLowLimit)
        {
            if (GetActiveThreadCountFromCombination(Volatile.Read(ref _dieSlotActiveFullThreadCountCombination)) <= threadCountLowLimit)
            {
                return(false);
            }

            bool result = false;

            lock (_syncObject)
            {
                try { }
                finally
                {
                    if (DecrementActiveThreadCount(threadCountLowLimit))
                    {
                        _extThreadBlocker.AddExpectedWaiterCount(1);
                        //Console.WriteLine("Thread deactivated = " + ActiveThreadCount.ToString());
                        result = true;
                    }
                }
            }
            return(result);
        }
        public void TestFullCycle()
        {
            PartialThreadBlocker inst        = new PartialThreadBlocker(0);
            Barrier startBar                 = new Barrier(8 + 1);
            int     exitedCount              = 0;
            CancellationTokenSource tokenSrc = new CancellationTokenSource();

            Thread[] threads = new Thread[8];

            Func <int> sleepThCount = () =>
            {
                int result = 0;
                foreach (var th in threads)
                {
                    if ((th.ThreadState & ThreadState.WaitSleepJoin) != 0)
                    {
                        result++;
                    }
                }
                return(result);
            };

            for (int i = 0; i < threads.Length; i++)
            {
                threads[i] = new Thread(() =>
                {
                    startBar.SignalAndWait();
                    while (!tokenSrc.IsCancellationRequested)
                    {
                        inst.Wait();
                        SpinWaitHelper.SpinWait(1200);
                        Thread.Yield();
                    }
                    Interlocked.Increment(ref exitedCount);
                });

                threads[i].Start();
            }

            startBar.SignalAndWait();

            for (int i = 0; i < threads.Length; i++)
            {
                TimingAssert.AreEqual(5000, i, sleepThCount, "UP. Sleeping thread count != i");
                TimingAssert.AreEqual(5000, i, () => inst.RealWaiterCount, "UP. RealWaiterCount != i");
                TimingAssert.AreEqual(5000, i, () => inst.ExpectedWaiterCount, "UP. ExpectedWaiterCount != i");
                inst.AddExpectedWaiterCount(1);
                Thread.Sleep(10);
            }

            TimingAssert.AreEqual(5000, threads.Length, sleepThCount);
            TimingAssert.AreEqual(5000, threads.Length, () => inst.RealWaiterCount);
            TimingAssert.AreEqual(5000, threads.Length, () => inst.ExpectedWaiterCount);


            for (int i = threads.Length; i > 0; i--)
            {
                TimingAssert.AreEqual(5000, i, sleepThCount);
                TimingAssert.AreEqual(5000, i, () => inst.RealWaiterCount);
                TimingAssert.AreEqual(5000, i, () => inst.ExpectedWaiterCount);
                inst.SubstractExpectedWaiterCount(1);
                Thread.Sleep(10);
            }

            TimingAssert.AreEqual(5000, 0, sleepThCount, "Sleeping thread count != 0");
            TimingAssert.AreEqual(5000, 0, () => inst.RealWaiterCount, "RealWaiterCount != 0");
            TimingAssert.AreEqual(5000, 0, () => inst.ExpectedWaiterCount, "ExpectedWaiterCount != 0");


            tokenSrc.Cancel();

            TimingAssert.AreEqual(5000, threads.Length, () => Volatile.Read(ref exitedCount));
        }