public void TestBlockRequiredCount()
        {
            PartialThreadBlocker inst = new PartialThreadBlocker(4);
            Barrier startBar          = new Barrier(8 + 1);
            int     exitedCount       = 0;


            for (int i = 0; i < 8; i++)
            {
                Task.Run(() =>
                {
                    startBar.SignalAndWait();
                    inst.Wait();
                    Interlocked.Increment(ref exitedCount);
                });
            }

            startBar.SignalAndWait();
            Assert.IsTrue(SpinWait.SpinUntil(() => Volatile.Read(ref exitedCount) >= 4 && inst.RealWaiterCount >= 4, 4000));

            TimingAssert.AreEqual(5000, 8 - 4, () => Volatile.Read(ref exitedCount), "exitedCount != 8");
            TimingAssert.AreEqual(5000, 4, () => inst.ExpectedWaiterCount, "ExpectedWaiterCount != 4");
            TimingAssert.AreEqual(5000, 4, () => inst.RealWaiterCount, "RealWaiterCount != 4");

            inst.SetExpectedWaiterCount(0);

            TimingAssert.AreEqual(5000, 8, () => Volatile.Read(ref exitedCount), "exitedCount != 8");
            TimingAssert.AreEqual(5000, 0, () => inst.ExpectedWaiterCount, "ExpectedWaiterCount != 0");
            TimingAssert.AreEqual(5000, 0, () => inst.RealWaiterCount, "RealWaiterCount != 0");
        }
        public void TestIncreaseWaiters()
        {
            PartialThreadBlocker inst        = new PartialThreadBlocker(4);
            Barrier startBar                 = new Barrier(8 + 1);
            int     exitedCount              = 0;
            int     somethingWork            = 0;
            CancellationTokenSource tokenSrc = new CancellationTokenSource();

            for (int i = 0; i < 8; i++)
            {
                Task.Run(() =>
                {
                    startBar.SignalAndWait();
                    while (!tokenSrc.IsCancellationRequested)
                    {
                        inst.Wait();
                        Interlocked.Increment(ref somethingWork);
                        Thread.Sleep(10);
                    }
                    Interlocked.Increment(ref exitedCount);
                });
            }

            startBar.SignalAndWait();

            TimingAssert.AreEqual(5000, 4, () => inst.ExpectedWaiterCount);
            TimingAssert.AreEqual(5000, 4, () => inst.RealWaiterCount, "Real waiter count != 4 (can be caused by slow processing)");
            TimingAssert.IsTrue(5000, () => Volatile.Read(ref somethingWork) > 0);

            inst.SetExpectedWaiterCount(8);
            Assert.AreEqual(8, inst.ExpectedWaiterCount);

            TimingAssert.AreEqual(5000, 8, () => inst.RealWaiterCount);
            Interlocked.Exchange(ref somethingWork, 0);

            TimingAssert.IsTrue(5000, () => Volatile.Read(ref somethingWork) == 0);

            tokenSrc.Cancel();
            inst.SetExpectedWaiterCount(0);

            TimingAssert.AreEqual(5000, 8, () => Volatile.Read(ref exitedCount));
            TimingAssert.AreEqual(5000, 0, () => inst.ExpectedWaiterCount);
            TimingAssert.AreEqual(500, 0, () => inst.RealWaiterCount);
        }
        public void TestCycledBlockRequiredCount()
        {
            PartialThreadBlocker inst        = new PartialThreadBlocker(4);
            Barrier startBar                 = new Barrier(8 + 1);
            int     exitedCount              = 0;
            int     somethingWork            = 0;
            CancellationTokenSource tokenSrc = new CancellationTokenSource();

            for (int i = 0; i < 8; i++)
            {
                Task.Run(() =>
                {
                    startBar.SignalAndWait();
                    while (!tokenSrc.IsCancellationRequested)
                    {
                        inst.Wait();
                        Interlocked.Increment(ref somethingWork);
                        Thread.Sleep(10);
                    }
                    Interlocked.Increment(ref exitedCount);
                });
            }

            startBar.SignalAndWait();

            TimingAssert.AreEqual(5000, 4, () => inst.ExpectedWaiterCount);
            TimingAssert.AreEqual(5000, 4, () => inst.RealWaiterCount);
            TimingAssert.IsTrue(5000, () => Volatile.Read(ref somethingWork) > 0);

            tokenSrc.Cancel();
            inst.SetExpectedWaiterCount(0);

            TimingAssert.AreEqual(5000, 8, () => Volatile.Read(ref exitedCount));
            TimingAssert.AreEqual(5000, 0, () => inst.ExpectedWaiterCount);
            TimingAssert.AreEqual(5000, 0, () => inst.RealWaiterCount);
        }