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(); }
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(); }
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(); } }
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(); }
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(); } }
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)); }
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(); }
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(); }); }
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(); }