CreateGuardedThread() public static method

public static CreateGuardedThread ( Action &waitForThread, Action start ) : Thread
waitForThread Action
start Action
return Thread
        public static void AtomicDowngradeTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();
            TestLockCookie tlc = trwl.UpgradeToWriterLock();

            Action waitForWaitingWriter;
            Thread waitingWriter =
                ThreadTestHelpers.CreateGuardedThread(out waitForWaitingWriter, () =>
            {
                trwl.AcquireWriterLock();
                trwl.ReleaseWriterLock();
            });

            waitingWriter.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingWriter.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Downgrade to a read lock successfully while there is a waiting writer
            trwl.DowngradeFromWriterLock(tlc);

            // Releasing the read lock releases the waiting writer
            trwl.ReleaseReaderLock();
            waitForWaitingWriter();

            trwl.Dispose();
        }
        public static void WaitingWritersTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();

            Action acquireReleaseWriterLock =
                () =>
            {
                trwl.AcquireWriterLock();
                trwl.ReleaseWriterLock();
            };
            Action waitForWaitingWriter1, waitForWaitingWriter2;
            Thread waitingWriter1 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingWriter1, acquireReleaseWriterLock);
            Thread waitingWriter2 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingWriter2, acquireReleaseWriterLock);

            waitingWriter1.IsBackground = true;
            waitingWriter2.IsBackground = true;
            waitingWriter1.Start();
            waitingWriter2.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingWriter1.ThreadState & ThreadState.WaitSleepJoin) != 0);
            ThreadTestHelpers.WaitForCondition(() => (waitingWriter2.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Releasing the read lock releases a waiting writer, that writer releases its write lock, in turn releasing the
            // other writer
            trwl.ReleaseReaderLock();
            waitForWaitingWriter1();
            waitForWaitingWriter2();

            trwl.Dispose();
        }
        public static void AtomicRecursiveReaderTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();

            Action waitForWaitingWriter;
            Thread waitingWriter =
                ThreadTestHelpers.CreateGuardedThread(out waitForWaitingWriter, () =>
            {
                trwl.AcquireWriterLock();
                trwl.ReleaseWriterLock();
            });

            waitingWriter.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingWriter.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Acquire a recursive read lock successfully while there is a waiting writer
            trwl.AcquireReaderLock();

            // Releasing both read locks releases the waiting writer
            trwl.ReleaseLock();
            waitForWaitingWriter();

            trwl.Dispose();
        }
Example #4
0
        public void InterlockedAddAndRead_Multithreaded_Int64()
        {
            const int  ThreadCount    = 10;
            const int  IterationCount = 100;
            const long Increment      = ((long)1 << 32) + 1;

            long   value                = 0;
            var    threadStarted        = new AutoResetEvent(false);
            var    startTest            = new ManualResetEvent(false);
            int    completedThreadCount = 0;
            Action threadStart          = () =>
            {
                threadStarted.Set();
                startTest.CheckedWait();
                for (int i = 0; i < IterationCount; ++i)
                {
                    Interlocked.Add(ref value, Increment);
                }

                Interlocked.Increment(ref completedThreadCount);
            };

            var checksForThreadErrors = new Action[ThreadCount];
            var waitsForThread        = new Action[ThreadCount];

            for (int i = 0; i < ThreadCount; ++i)
            {
                Thread t =
                    ThreadTestHelpers.CreateGuardedThread(out checksForThreadErrors[i], out waitsForThread[i], threadStart);
                t.IsBackground = true;
                t.Start();
                threadStarted.CheckedWait();
            }

            startTest.Set();
            ThreadTestHelpers.WaitForConditionWithCustomDelay(
                () => completedThreadCount >= ThreadCount,
                () =>
            {
                long valueSnapshot = Interlocked.Read(ref value);
                Assert.Equal((int)valueSnapshot, (int)(valueSnapshot >> 32));

                foreach (var checkForThreadErrors in checksForThreadErrors)
                {
                    checkForThreadErrors();
                }

                Thread.Sleep(1);
            });
            foreach (var waitForThread in waitsForThread)
            {
                waitForThread();
            }

            Assert.Equal(ThreadCount, completedThreadCount);
            Assert.Equal(ThreadCount * IterationCount * Increment, Interlocked.Read(ref value));
        }
        public static void ReadersWaitingOnWaitingUpgraderTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();

            var    waitingUpgraderReady    = new AutoResetEvent(false);
            var    continueWaitingUpgrader = new AutoResetEvent(false);
            Action waitForWaitingUpgrader;
            Thread waitingUpgrader =
                ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader, () =>
            {
                trwl.AcquireReaderLock();
                trwl.UpgradeToWriterLock();
                waitingUpgraderReady.Set();
                continueWaitingUpgrader.CheckedWait();
                trwl.ReleaseWriterLock();
                trwl.VerifyIsReaderLockHeld(false);
                trwl.VerifyIsWriterLockHeld(false);
            });

            waitingUpgrader.IsBackground = true;
            waitingUpgrader.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader.ThreadState & ThreadState.WaitSleepJoin) != 0);

            Action acquireReleaseReaderLock =
                () =>
            {
                trwl.AcquireReaderLock();
                trwl.ReleaseReaderLock();
            };
            Action waitForWaitingReader1, waitForWaitingReader2;
            Thread waitingReader1 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingReader1, acquireReleaseReaderLock);
            Thread waitingReader2 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingReader2, acquireReleaseReaderLock);

            waitingReader1.IsBackground = true;
            waitingReader2.IsBackground = true;
            waitingReader1.Start();
            waitingReader2.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingReader1.ThreadState & ThreadState.WaitSleepJoin) != 0);
            ThreadTestHelpers.WaitForCondition(() => (waitingReader2.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Releasing the read lock releases the waiting upgrader
            trwl.ReleaseReaderLock();
            waitingUpgraderReady.CheckedWait();

            // Releasing the now-writer's write lock releases all waiting readers
            continueWaitingUpgrader.Set();
            waitForWaitingUpgrader();
            waitForWaitingReader1();
            waitForWaitingReader2();

            trwl.Dispose();
        }
Example #6
0
        public static void TimersCreatedConcurrentlyOnDifferentThreadsAllFire()
        {
            int processorCount = Environment.ProcessorCount;

            int           timerTickCount = 0;
            TimerCallback timerCallback  = data => Interlocked.Increment(ref timerTickCount);

            var             threadStarted          = new AutoResetEvent(false);
            var             createTimers           = new ManualResetEvent(false);
            var             timers                 = new Timer[processorCount];
            Action <object> createTimerThreadStart = data =>
            {
                int i  = (int)data;
                var sw = new Stopwatch();
                threadStarted.Set();
                createTimers.WaitOne();

                // Use the CPU a bit around creating the timer to try to have some of these threads run concurrently
                sw.Restart();
                do
                {
                    Thread.SpinWait(1000);
                } while (sw.ElapsedMilliseconds < 10);

                timers[i] = new Timer(timerCallback, null, 1, Timeout.Infinite);

                // Use the CPU a bit around creating the timer to try to have some of these threads run concurrently
                sw.Restart();
                do
                {
                    Thread.SpinWait(1000);
                } while (sw.ElapsedMilliseconds < 10);
            };

            var waitsForThread = new Action[timers.Length];

            for (int i = 0; i < timers.Length; ++i)
            {
                var t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], createTimerThreadStart);
                t.IsBackground = true;
                t.Start(i);
                threadStarted.CheckedWait();
            }

            createTimers.Set();
            ThreadTestHelpers.WaitForCondition(() => timerTickCount == timers.Length);

            foreach (var waitForThread in waitsForThread)
            {
                waitForThread();
            }
        }
Example #7
0
        public void InterlockedCompareExchange_Multithreaded_Double()
        {
            const int    ThreadCount    = 10;
            const int    IterationCount = 100;
            const double Increment      = ((long)1 << 32) + 1;

            double value         = 0;
            var    threadStarted = new AutoResetEvent(false);
            var    startTest     = new ManualResetEvent(false);
            Action threadStart   = () =>
            {
                threadStarted.Set();
                startTest.CheckedWait();
                for (int i = 0; i < IterationCount; ++i)
                {
                    double oldValue = value;
                    while (true)
                    {
                        double valueBeforeUpdate = Interlocked.CompareExchange(ref value, oldValue + Increment, oldValue);
                        if (valueBeforeUpdate == oldValue)
                        {
                            break;
                        }

                        oldValue = valueBeforeUpdate;
                    }
                }
            };

            var waitsForThread = new Action[ThreadCount];

            for (int i = 0; i < ThreadCount; ++i)
            {
                Thread t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], threadStart);
                t.IsBackground = true;
                t.Start();
                threadStarted.CheckedWait();
            }

            startTest.Set();
            foreach (var waitForThread in waitsForThread)
            {
                waitForThread();
            }

            Assert.Equal(ThreadCount * IterationCount * Increment, Interlocked.CompareExchange(ref value, 0, 0));
        }
        public static void WaitingUpgradersTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();

            var    waitingUpgrader1AcquiredReadLock = new ManualResetEvent(false);
            Action waitForWaitingUpgrader1, waitForWaitingUpgrader2, waitForWaitingUpgrader3;
            Thread waitingUpgrader1 =
                ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader1, () =>
            {
                trwl.AcquireReaderLock();
                waitingUpgrader1AcquiredReadLock.Set();
                TestLockCookie tlc = trwl.UpgradeToWriterLock();
                trwl.DowngradeFromWriterLock(tlc);
                trwl.ReleaseReaderLock();
            });
            Action upgradeDowngradeLock =
                () =>
            {
                TestLockCookie tlc = trwl.UpgradeToWriterLock();
                trwl.DowngradeFromWriterLock(tlc);
            };
            Thread waitingUpgrader2 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader2, upgradeDowngradeLock);
            Thread waitingUpgrader3 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader3, upgradeDowngradeLock);

            waitingUpgrader1.IsBackground = true;
            waitingUpgrader2.IsBackground = true;
            waitingUpgrader1.Start();
            waitingUpgrader1AcquiredReadLock.CheckedWait();
            waitingUpgrader2.Start();
            waitingUpgrader3.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader1.ThreadState & ThreadState.WaitSleepJoin) != 0);
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader2.ThreadState & ThreadState.WaitSleepJoin) != 0);
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader3.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Releasing the read lock releases a waiting upgrader, that writer downgrades its write lock, in turn releasing the
            // other upgrader, and so on
            trwl.ReleaseReaderLock();
            waitForWaitingUpgrader1();
            waitForWaitingUpgrader2();
            waitForWaitingUpgrader3();

            trwl.Dispose();
        }
Example #9
0
        public void NamedMutex_DisposeWhenLockedRaceTest()
        {
            var mutexName  = Guid.NewGuid().ToString("N");
            var mutex2Name = mutexName + "_2";

            var waitsForThread = new Action[Environment.ProcessorCount];

            for (int i = 0; i < waitsForThread.Length; ++i)
            {
                var t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], () =>
                {
                    for (int i = 0; i < 1000; ++i)
                    {
                        // Create or open two mutexes with different names, acquire the lock if created, and dispose without
                        // releasing the lock. What may occasionally happen is, one thread T0 will acquire the lock, another
                        // thread T1 will open the same mutex, T0 will dispose its mutex while the lock is held, and T1 will
                        // then release the last reference to the mutex. On some implementations T1 may not be able to destroy
                        // the mutex when it is still locked by T0, or there may be potential for races in the sequence. This
                        // test only looks for errors from race conditions.
                        using (var mutex = new Mutex(true, mutexName))
                        {
                        }
                        using (var mutex = new Mutex(true, mutex2Name))
                        {
                        }
                    }
                });
                t.IsBackground = true;
                t.Start();
            }

            foreach (var waitForThread in waitsForThread)
            {
                waitForThread();
            }
        }
Example #10
0
        public void InterlockedIncrement_Multithreaded_Int32()
        {
            const int ThreadCount    = 10;
            const int IterationCount = 100;

            int    value         = 0;
            var    threadStarted = new AutoResetEvent(false);
            var    startTest     = new ManualResetEvent(false);
            Action threadStart   = () =>
            {
                threadStarted.Set();
                startTest.CheckedWait();
                for (int i = 0; i < IterationCount; ++i)
                {
                    Interlocked.Increment(ref value);
                }
            };

            var waitsForThread = new Action[ThreadCount];

            for (int i = 0; i < ThreadCount; ++i)
            {
                Thread t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], threadStart);
                t.IsBackground = true;
                t.Start();
                threadStarted.CheckedWait();
            }

            startTest.Set();
            foreach (var waitForThread in waitsForThread)
            {
                waitForThread();
            }

            Assert.Equal(ThreadCount * IterationCount, Interlocked.CompareExchange(ref value, 0, 0));
        }
Example #11
0
        public static void Enter_HasToWait()
        {
            var thinLock  = new object();
            var awareLock = new object();

            // Actually transition the aware lock to an aware lock by having a background thread wait for a lock
            {
                Action waitForThread;
                Thread t =
                    ThreadTestHelpers.CreateGuardedThread(out waitForThread, () =>
                                                          Assert.False(Monitor.TryEnter(awareLock, ThreadTestHelpers.ExpectedTimeoutMilliseconds)));
                t.IsBackground = true;
                lock (awareLock)
                {
                    t.Start();
                    waitForThread();
                }
            }

            // When the current thread has the lock, have background threads wait for the lock in various ways. After a short
            // duration, release the lock and allow the background threads to acquire the lock.
            {
                var     backgroundTestDelegates = new List <Action <object> >();
                Barrier readyBarrier            = null;

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    Monitor.Enter(lockObj);
                    Monitor.Exit(lockObj);
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    bool lockTaken = false;
                    Monitor.Enter(lockObj, ref lockTaken);
                    Assert.True(lockTaken);
                    Monitor.Exit(lockObj);
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    lock (lockObj)
                    {
                    }
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    Assert.True(Monitor.TryEnter(lockObj, ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
                    Monitor.Exit(lockObj);
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    Assert.True(
                        Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)));
                    Monitor.Exit(lockObj);
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    bool lockTaken = false;
                    Monitor.TryEnter(lockObj, ThreadTestHelpers.UnexpectedTimeoutMilliseconds, ref lockTaken);
                    Assert.True(lockTaken);
                    Monitor.Exit(lockObj);
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    bool lockTaken = false;
                    Monitor.TryEnter(
                        lockObj,
                        TimeSpan.FromMilliseconds(ThreadTestHelpers.UnexpectedTimeoutMilliseconds),
                        ref lockTaken);
                    Assert.True(lockTaken);
                    Monitor.Exit(lockObj);
                });

                int testCount = backgroundTestDelegates.Count * 2; // two iterations each, one for thin lock and one for aware lock
                readyBarrier = new Barrier(testCount + 1);         // plus main thread
                var waitForThreadArray = new Action[testCount];
                for (int i = 0; i < backgroundTestDelegates.Count; ++i)
                {
                    int    icopy = i; // for use in delegates
                    Thread t     =
                        ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2],
                                                              () => backgroundTestDelegates[icopy](thinLock));
                    t.IsBackground = true;
                    t.Start();
                    t = ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2 + 1],
                                                              () => backgroundTestDelegates[icopy](awareLock));
                    t.IsBackground = true;
                    t.Start();
                }

                lock (thinLock)
                {
                    lock (awareLock)
                    {
                        readyBarrier.SignalAndWait(ThreadTestHelpers.UnexpectedTimeoutMilliseconds);
                        Thread.Sleep(ThreadTestHelpers.ExpectedTimeoutMilliseconds);
                    }
                }
                foreach (Action waitForThread in waitForThreadArray)
                {
                    waitForThread();
                }
            }

            // When the current thread has the lock, have background threads wait for the lock in various ways and time out
            // after a short duration
            {
                var     backgroundTestDelegates = new List <Action <object> >();
                Barrier readyBarrier            = null;

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    Assert.False(Monitor.TryEnter(lockObj, ThreadTestHelpers.ExpectedTimeoutMilliseconds));
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    Assert.False(
                        Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(ThreadTestHelpers.ExpectedTimeoutMilliseconds)));
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    bool lockTaken = false;
                    Monitor.TryEnter(lockObj, ThreadTestHelpers.ExpectedTimeoutMilliseconds, ref lockTaken);
                    Assert.False(lockTaken);
                });

                backgroundTestDelegates.Add(lockObj =>
                {
                    readyBarrier.SignalAndWait();
                    bool lockTaken = false;
                    Monitor.TryEnter(
                        lockObj,
                        TimeSpan.FromMilliseconds(ThreadTestHelpers.ExpectedTimeoutMilliseconds),
                        ref lockTaken);
                    Assert.False(lockTaken);
                });

                int testCount = backgroundTestDelegates.Count * 2; // two iterations each, one for thin lock and one for aware lock
                readyBarrier = new Barrier(testCount + 1);         // plus main thread
                var waitForThreadArray = new Action[testCount];
                for (int i = 0; i < backgroundTestDelegates.Count; ++i)
                {
                    int    icopy = i; // for use in delegates
                    Thread t     =
                        ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2],
                                                              () => backgroundTestDelegates[icopy](thinLock));
                    t.IsBackground = true;
                    t.Start();
                    t = ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2 + 1],
                                                              () => backgroundTestDelegates[icopy](awareLock));
                    t.IsBackground = true;
                    t.Start();
                }

                lock (thinLock)
                {
                    lock (awareLock)
                    {
                        readyBarrier.SignalAndWait(ThreadTestHelpers.UnexpectedTimeoutMilliseconds);
                        foreach (Action waitForThread in waitForThreadArray)
                        {
                            waitForThread();
                        }
                    }
                }
            }
        }
        public static void BasicLockTest()
        {
            var            trwl = new TestReaderWriterLock();
            TestLockCookie tlc;
            var            threadReady = new AutoResetEvent(false);
            var            continueThread = new AutoResetEvent(false);
            Action         checkForThreadErrors, waitForThread;
            Thread         t =
                ThreadTestHelpers.CreateGuardedThread(out checkForThreadErrors, out waitForThread, () =>
            {
                TestLockCookie tlc2;
                Action switchToMainThread =
                    () =>
                {
                    threadReady.Set();
                    continueThread.CheckedWait();
                };

                switchToMainThread();

                // Multiple readers from multiple threads
                {
                    trwl.AcquireReaderLock();
                    trwl.AcquireReaderLock();
                    switchToMainThread();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    trwl.AcquireReaderLock();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();
                }

                // What can be done when a read lock is held
                {
                    trwl.AcquireReaderLock();
                    switchToMainThread();

                    // Any thread can take a read lock
                    trwl.AcquireReaderLock();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    // No thread can take a write lock
                    trwl.AcquireWriterLock(TimeoutExceptionHResult);
                    trwl.AcquireReaderLock();
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    // Owning thread releases read lock when upgrading
                    trwl.AcquireWriterLock();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();

                    // Owning thread cannot upgrade if there are other readers or writers
                    trwl.AcquireReaderLock();
                    switchToMainThread();
                    trwl.ReleaseReaderLock();
                    trwl.AcquireWriterLock();
                    switchToMainThread();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();
                }

                // What can be done when a write lock is held
                {
                    // Write lock acquired through AcquireWriteLock is exclusive
                    trwl.AcquireWriterLock();
                    switchToMainThread();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();

                    // Write lock acquired through upgrading is also exclusive
                    trwl.AcquireReaderLock();
                    tlc2 = trwl.UpgradeToWriterLock();
                    switchToMainThread();
                    trwl.DowngradeFromWriterLock(tlc2);
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    // Write lock acquired through restore is also exclusive
                    trwl.AcquireWriterLock();
                    tlc = trwl.ReleaseLock();
                    trwl.RestoreLock(tlc);
                    switchToMainThread();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();
                }
            });

            t.IsBackground = true;
            t.Start();

            Action beginSwitchToBackgroundThread = () => continueThread.Set();
            Action endSwitchToBackgroundThread   =
                () =>
            {
                try
                {
                    threadReady.CheckedWait();
                }
                finally
                {
                    checkForThreadErrors();
                }
            };
            Action switchToBackgroundThread =
                () =>
            {
                beginSwitchToBackgroundThread();
                endSwitchToBackgroundThread();
            };

            endSwitchToBackgroundThread();

            // Multiple readers from muliple threads
            {
                trwl.AcquireReaderLock();
                trwl.AcquireReaderLock();
                switchToBackgroundThread(); // AcquireReaderLock * 2
                trwl.ReleaseReaderLock();
                switchToBackgroundThread(); // ReleaseReaderLock

                // Release/restore the read lock while a read lock is held by another thread
                tlc = trwl.ReleaseLock();
                trwl.RestoreLock(tlc);

                switchToBackgroundThread(); // ReleaseReaderLock

                // Downgrade to read lock allows another thread to acquire read lock
                tlc = trwl.UpgradeToWriterLock();
                trwl.DowngradeFromWriterLock(tlc);
                switchToBackgroundThread(); // AcquireReaderLock, ReleaseReaderLock

                trwl.ReleaseReaderLock();
            }

            // What can be done when a read lock is held
            {
                switchToBackgroundThread(); // AcquireReaderLock
                {
                    // Any thread can take a read lock
                    trwl.AcquireReaderLock();
                    trwl.ReleaseReaderLock();
                    switchToBackgroundThread(); // same as above

                    // No thread can take a write lock
                    trwl.AcquireWriterLock(TimeoutExceptionHResult);
                    trwl.AcquireReaderLock();
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                    switchToBackgroundThread(); // same as above
                    trwl.ReleaseReaderLock();

                    // Other threads cannot upgrade to a write lock, but the owning thread can
                    trwl.AcquireReaderLock();
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                    trwl.ReleaseReaderLock();
                }
                switchToBackgroundThread(); // ReleaseReaderLock

                // Owning thread releases read lock when upgrading
                trwl.AcquireReaderLock();
                beginSwitchToBackgroundThread(); // AcquireWriterLock: background thread gets blocked
                trwl.UpgradeToWriterLock();      // unblocks background thread: ReleaseWriterLock
                trwl.ReleaseWriterLock();
                endSwitchToBackgroundThread();

                // Owning thread cannot upgrade if there are other readers or writers
                trwl.AcquireReaderLock();
                switchToBackgroundThread(); // AcquireReaderLock
                trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                trwl.ReleaseReaderLock();
                switchToBackgroundThread(); // ReleaseReaderLock, AcquireWriterLock
                trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                switchToBackgroundThread(); // ReleaseWriterLock
            }

            // What can be done when a write lock is held
            {
                trwl.AcquireWriterLock();
                TestLockCookie restoreToWriteLockTlc   = trwl.ReleaseLock();
                Action         verifyCannotAcquireLock =
                    () =>
                {
                    trwl.AcquireReaderLock(TimeoutExceptionHResult);
                    trwl.AcquireWriterLock(TimeoutExceptionHResult);
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                };
                Action verifyCanAcquireLock =
                    () =>
                {
                    trwl.AcquireReaderLock();
                    tlc = trwl.UpgradeToWriterLock();
                    trwl.DowngradeFromWriterLock(tlc);
                    trwl.ReleaseReaderLock();
                    trwl.AcquireWriterLock();
                    trwl.ReleaseWriterLock();
                    trwl.RestoreLock(restoreToWriteLockTlc.Clone());
                    trwl.ReleaseWriterLock();
                };

                // Write lock acquired through AcquireWriteLock is exclusive
                switchToBackgroundThread(); // AcquireWriterLock
                verifyCannotAcquireLock();
                switchToBackgroundThread(); // ReleaseWriterLock
                verifyCanAcquireLock();

                // Write lock acquired through upgrading is also exclusive
                switchToBackgroundThread(); // AcquireReaderLock, UpgradeToWriterLock
                verifyCannotAcquireLock();
                switchToBackgroundThread(); // DowngradeFromWriterLock, ReleaseReaderLock
                verifyCanAcquireLock();

                // Write lock acquired through restore is also exclusive
                switchToBackgroundThread(); // AcquireWriterLock, ReleaseLock, RestoreLock
                verifyCannotAcquireLock();
                switchToBackgroundThread(); // ReleaseWriterLock
                verifyCanAcquireLock();
            }

            beginSwitchToBackgroundThread();
            waitForThread();
            trwl.Dispose();
        }
Example #13
0
        public static void ValuesGetterDoesNotThrowUnexpectedExceptionWhenDisposed()
        {
            var startTest = new ManualResetEvent(false);
            var gotUnexpectedException    = new ManualResetEvent(false);
            ThreadLocal <int> threadLocal = null;
            bool stop = false;

            Action waitForCreatorDisposer;
            Thread creatorDisposer = ThreadTestHelpers.CreateGuardedThread(out waitForCreatorDisposer, () =>
            {
                startTest.CheckedWait();
                do
                {
                    var tl = new ThreadLocal <int>(trackAllValues: true);
                    Volatile.Write(ref threadLocal, tl);
                    tl.Value = 1;
                    tl.Dispose();
                } while (!Volatile.Read(ref stop));
            });

            creatorDisposer.IsBackground = true;
            creatorDisposer.Start();

            int readerCount    = Math.Max(1, Environment.ProcessorCount - 1);
            var waitsForReader = new Action[readerCount];

            for (int i = 0; i < readerCount; ++i)
            {
                Thread reader = ThreadTestHelpers.CreateGuardedThread(out waitsForReader[i], () =>
                {
                    startTest.CheckedWait();
                    do
                    {
                        var tl = Volatile.Read(ref threadLocal);
                        if (tl == null)
                        {
                            continue;
                        }

                        try
                        {
                            IList <int> values = tl.Values;
                        }
                        catch (ObjectDisposedException)
                        {
                        }
                        catch
                        {
                            gotUnexpectedException.Set();
                            throw;
                        }
                    } while (!Volatile.Read(ref stop));
                });
                reader.IsBackground = true;
                reader.Start();
            }

            startTest.Set();
            bool failed = gotUnexpectedException.WaitOne(500);

            Volatile.Write(ref stop, true);
            foreach (Action waitForReader in waitsForReader)
            {
                waitForReader();
            }
            waitForCreatorDisposer();
            Assert.False(failed);
        }
        public static void WaitNotificationTest()
        {
            ThreadTestHelpers.RunTestInBackgroundThread(() =>
            {
                var tsc = new TestSynchronizationContext();
                SynchronizationContext.SetSynchronizationContext(tsc);
                Assert.Same(tsc, SynchronizationContext.Current);

                var e          = new ManualResetEvent(false);
                tsc.WaitAction = () => e.Set();
                Assert.False(tsc.IsWaitNotificationRequired());
                Assert.False(e.WaitOne(0));
                tsc.SetWaitNotificationRequired();
                Assert.True(tsc.IsWaitNotificationRequired());
                Assert.True(e.WaitOne(0));

                var mres       = new ManualResetEventSlim();
                tsc.WaitAction = () => mres.Set();
                mres.Reset();
                mres.CheckedWait();

                e.Reset();
                tsc.WaitAction = () => e.Set();
                SynchronizationContext.SetSynchronizationContext(new TestSynchronizationContext());
                Assert.False(e.WaitOne(0));
                SynchronizationContext.SetSynchronizationContext(tsc);
                Assert.True(e.WaitOne(0));
                e.Reset();
                e.CheckedWait();

                e.Reset();
                var lockObj = new object();
                var lockAcquiredFromBackground = new AutoResetEvent(false);
                Action waitForThread;
                Thread t =
                    ThreadTestHelpers.CreateGuardedThread(out waitForThread, () =>
                {
                    lock (lockObj)
                    {
                        lockAcquiredFromBackground.Set();
                        e.CheckedWait();
                    }
                });
                t.IsBackground = true;
                t.Start();
                lockAcquiredFromBackground.CheckedWait();
                Assert.True(Monitor.TryEnter(lockObj, ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
                Monitor.Exit(lockObj);
                waitForThread();

                e.Reset();
                var m = new Mutex();
                t     = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () =>
                {
                    m.CheckedWait();
                    try
                    {
                        lockAcquiredFromBackground.Set();
                        e.CheckedWait();
                    }
                    finally
                    {
                        m.ReleaseMutex();
                    }
                });
                t.IsBackground = true;
                t.Start();
                lockAcquiredFromBackground.CheckedWait();
                m.CheckedWait();
                m.ReleaseMutex();
                waitForThread();
            });
        }
Example #15
0
        public void CountTest()
        {
            RemoteExecutor.Invoke(() =>
            {
                const int TimersPerThread = 64;
                int processorCount        = Environment.ProcessorCount;
                int totalTimerCount       = processorCount * TimersPerThread;

                var timers = new List <Timer>(totalTimerCount);
                TimerCallback timerCallback   = _ => { };
                var startCreateTimerThreads   = new ManualResetEvent(false);
                Action createTimerThreadStart = () =>
                {
                    startCreateTimerThreads.WaitOne();
                    for (int i = 0; i < TimersPerThread; ++i)
                    {
                        lock (timers)
                        {
                            timers.Add(
                                new Timer(
                                    timerCallback,
                                    null,
                                    ThreadTestHelpers.UnexpectedTimeoutMilliseconds,
                                    ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
                            Assert.True(Timer.ActiveCount >= timers.Count);
                        }
                    }
                };
                var waitsForThread = new Action[processorCount];
                for (int i = 0; i < processorCount; ++i)
                {
                    Thread t       = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], createTimerThreadStart);
                    t.IsBackground = true;
                    t.Start();
                }

                startCreateTimerThreads.Set();
                foreach (Action waitForThread in waitsForThread)
                {
                    waitForThread();
                }

                // To leave some room for unknown timers to be scheduled and removed, remove a large number of timers at a time and
                // verify that the timer count has decreased
                while (timers.Count > 0)
                {
                    long timerCountBeforeRemove = Timer.ActiveCount;
                    int endIndex = timers.Count - processorCount * 8;
                    for (int i = timers.Count - 1; i >= Math.Max(0, endIndex); --i)
                    {
                        timers[i].Dispose();
                        timers.RemoveAt(i);
                    }

                    if (endIndex >= 0)
                    {
                        Assert.True(Timer.ActiveCount < timerCountBeforeRemove);
                    }
                }
            }).Dispose();
        }