public static void BlockingUnregisterBlocksWhileCallbackIsRunning() { var waitEvent = new AutoResetEvent(false); var waitCallbackProgressMade = new AutoResetEvent(false); var completeWaitCallback = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, __) => { waitCallbackProgressMade.Set(); completeWaitCallback.WaitOne(UnexpectedTimeoutMilliseconds); waitCallbackProgressMade.Set(); }, null, UnexpectedTimeoutMilliseconds, false); waitEvent.Set(); waitCallbackProgressMade.CheckedWait(); // one callback running waitEvent.Set(); waitCallbackProgressMade.CheckedWait(); // two callbacks running Thread t = ThreadTestHelpers.CreateGuardedThread(out Action waitForThread, () => Assert.True(registeredWaitHandle.Unregister(new InvalidWaitHandle()))); t.IsBackground = true; t.Start(); Assert.False(t.Join(ExpectedTimeoutMilliseconds)); completeWaitCallback.Set(); // complete one callback waitCallbackProgressMade.CheckedWait(); Assert.False(t.Join(ExpectedTimeoutMilliseconds)); completeWaitCallback.Set(); // complete other callback waitCallbackProgressMade.CheckedWait(); waitForThread(); }
public static void UnregisterWaitHandleIsNotSignaledWhenCallbackIsRunning() { var waitEvent = new AutoResetEvent(false); var waitCallbackProgressMade = new AutoResetEvent(false); var completeWaitCallback = new AutoResetEvent(false); var waitUnregistered = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, __) => { waitCallbackProgressMade.Set(); completeWaitCallback.WaitOne(UnexpectedTimeoutMilliseconds); waitCallbackProgressMade.Set(); }, null, UnexpectedTimeoutMilliseconds, false); waitEvent.Set(); waitCallbackProgressMade.CheckedWait(); // one callback running waitEvent.Set(); waitCallbackProgressMade.CheckedWait(); // two callbacks running Assert.True(registeredWaitHandle.Unregister(waitUnregistered)); Assert.False(waitUnregistered.WaitOne(ExpectedTimeoutMilliseconds)); completeWaitCallback.Set(); // complete one callback waitCallbackProgressMade.CheckedWait(); Assert.False(waitUnregistered.WaitOne(ExpectedTimeoutMilliseconds)); completeWaitCallback.Set(); // complete other callback waitCallbackProgressMade.CheckedWait(); waitUnregistered.CheckedWait(); }
public void WaitTest() { var e = new AutoResetEvent(true); e.CheckedWait(); Assert.False(e.WaitOne(0)); e.Set(); e.CheckedWait(); Assert.False(e.WaitOne(0)); e.Reset(); Assert.False(e.WaitOne(ThreadTestHelpers.ExpectedTimeoutMilliseconds)); }
public static void UnregisterEventSignaledWhenUnregistered() { var waitEvent = new AutoResetEvent(false); var waitCallbackInvoked = new AutoResetEvent(false); var waitUnregistered = new AutoResetEvent(false); bool timedOut = false; WaitOrTimerCallback waitCallback = (_, timedOut2) => { timedOut = timedOut2; waitCallbackInvoked.Set(); }; // executeOnlyOnce = true, no timeout and no callback invocation var registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, waitCallback, null, Timeout.Infinite, executeOnlyOnce: true); Assert.False(waitCallbackInvoked.WaitOne(ExpectedTimeoutMilliseconds)); Assert.True(registeredWaitHandle.Unregister(waitUnregistered)); waitUnregistered.CheckedWait(); Assert.False(timedOut); // executeOnlyOnce = true, no timeout with callback invocation registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, waitCallback, null, Timeout.Infinite, executeOnlyOnce: true); waitEvent.Set(); waitCallbackInvoked.CheckedWait(); Assert.True(registeredWaitHandle.Unregister(waitUnregistered)); waitUnregistered.CheckedWait(); Assert.False(timedOut); // executeOnlyOnce = true, with timeout registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( waitEvent, waitCallback, null, ExpectedTimeoutMilliseconds, executeOnlyOnce: true); waitCallbackInvoked.CheckedWait(); Assert.False(waitCallbackInvoked.WaitOne(ExpectedTimeoutMilliseconds)); Assert.True(registeredWaitHandle.Unregister(waitUnregistered)); waitUnregistered.CheckedWait(); Assert.True(timedOut); timedOut = false; // executeOnlyOnce = false registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( waitEvent, waitCallback, null, UnexpectedTimeoutMilliseconds, executeOnlyOnce: false); Assert.False(waitCallbackInvoked.WaitOne(ExpectedTimeoutMilliseconds)); Assert.True(registeredWaitHandle.Unregister(waitUnregistered)); waitUnregistered.CheckedWait(); Assert.False(timedOut); }
private static void VerifyExecutionContextFlow(AsyncLocal <int> asyncLocal, int expectedValue) { Assert.Equal(expectedValue == 0, ExecutionContext.IsFlowSuppressed()); if (ExecutionContext.IsFlowSuppressed()) { Assert.Null(ExecutionContext.Capture()); } VerifyExecutionContext(ExecutionContext.Capture(), asyncLocal, expectedValue); // Creating a thread flows context if and only if flow is not suppressed int asyncLocalValue = -1; ThreadTestHelpers.RunTestInBackgroundThread(() => asyncLocalValue = asyncLocal.Value); Assert.Equal(expectedValue, asyncLocalValue); // Queueing a thread pool work item flows context if and only if flow is not suppressed asyncLocalValue = -1; var done = new AutoResetEvent(false); ThreadPool.QueueUserWorkItem(state => { asyncLocalValue = asyncLocal.Value; done.Set(); }); done.CheckedWait(); Assert.Equal(expectedValue, asyncLocalValue); }
public static void StartTest() { var e = new AutoResetEvent(false); Action waitForThread; Thread t = null; t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => { e.CheckedWait(); Assert.Same(t, Thread.CurrentThread); }); t.IsBackground = true; Assert.Throws <InvalidOperationException>(() => t.Start(null)); Assert.Throws <InvalidOperationException>(() => t.Start(t)); t.Start(); Assert.Throws <ThreadStateException>(() => t.Start()); e.Set(); waitForThread(); Assert.Throws <ThreadStateException>(() => t.Start()); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => e.CheckedWait()); t.IsBackground = true; t.Start(); Assert.Throws <ThreadStateException>(() => t.Start()); Assert.Throws <ThreadStateException>(() => t.Start(null)); Assert.Throws <ThreadStateException>(() => t.Start(t)); e.Set(); waitForThread(); Assert.Throws <ThreadStateException>(() => t.Start()); Assert.Throws <ThreadStateException>(() => t.Start(null)); Assert.Throws <ThreadStateException>(() => t.Start(t)); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => { Assert.Null(parameter); Assert.Same(t, Thread.CurrentThread); }); t.IsBackground = true; t.Start(); waitForThread(); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => { Assert.Null(parameter); Assert.Same(t, Thread.CurrentThread); }); t.IsBackground = true; t.Start(null); waitForThread(); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => { Assert.Same(t, parameter); Assert.Same(t, Thread.CurrentThread); }); t.IsBackground = true; t.Start(t); waitForThread(); }
public static void WaitWithLongerTimeoutThanWaitThreadCanStillTimeout() { AutoResetEvent e0 = new AutoResetEvent(false); ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(false), (_, __) => e0.Set(), null, WaitThreadTimeoutTimeMs + 1000, true); Thread.Sleep(WaitThreadTimeoutTimeMs); e0.CheckedWait(); }
public static void InterruptTest() { // Interrupting a thread that is not blocked does not do anything, but once the thread starts blocking, it gets // interrupted var threadReady = new AutoResetEvent(false); var continueThread = new AutoResetEvent(false); bool continueThreadBool = false; Action waitForThread; var t = CreateGuardedThread(out waitForThread, () => { threadReady.Set(); WaitForConditionWithoutBlocking(() => Volatile.Read(ref continueThreadBool)); threadReady.Set(); Assert.Throws <ThreadInterruptedException>(() => continueThread.CheckedWait()); }); t.IsBackground = true; t.Start(); threadReady.CheckedWait(); t.Interrupt(); Assert.False(threadReady.WaitOne(ExpectedTimeoutMilliseconds)); Volatile.Write(ref continueThreadBool, true); waitForThread(); // Interrupting a dead thread does nothing t.Interrupt(); // Interrupting an unstarted thread causes the thread to be interrupted after it is started and starts blocking t = CreateGuardedThread(out waitForThread, () => Assert.Throws <ThreadInterruptedException>(() => continueThread.CheckedWait())); t.IsBackground = true; t.Interrupt(); t.Start(); waitForThread(); // A thread that is already blocked on a synchronization primitive unblocks immediately continueThread.Reset(); t = CreateGuardedThread(out waitForThread, () => Assert.Throws <ThreadInterruptedException>(() => continueThread.CheckedWait())); t.IsBackground = true; t.Start(); WaitForCondition(() => (t.ThreadState & ThreadState.WaitSleepJoin) != 0); t.Interrupt(); waitForThread(); }
public void NamedMutex_ThreadExitDisposeRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); for (int i = 0; i < 1000; ++i) { var m = new Mutex(false, mutexName); var startParallelTest = new ManualResetEvent(false); var t0Ready = new AutoResetEvent(false); Thread t0 = ThreadTestHelpers.CreateGuardedThread(out Action waitForT0, () => { m.CheckedWait(); t0Ready.Set(); startParallelTest.CheckedWait(); // after this, exit T0 }); t0.IsBackground = true; var t1Ready = new AutoResetEvent(false); Thread t1 = ThreadTestHelpers.CreateGuardedThread(out Action waitForT1, () => { using (var m2 = Mutex.OpenExisting(mutexName)) { m.Dispose(); t1Ready.Set(); startParallelTest.CheckedWait(); // after this, close last handle to named mutex, exit T1 } }); t1.IsBackground = true; t0.Start(); t0Ready.CheckedWait(); // wait for T0 to acquire the mutex t1.Start(); t1Ready.CheckedWait(); // wait for T1 to open the existing mutex in a new mutex object and dispose one of the two // Release both threads at the same time. T0 will be exiting the thread, perhaps trying to abandon the mutex // that is still locked by it. In parallel, T1 will be disposing the last mutex instance, which would try to // destroy the mutex. startParallelTest.Set(); waitForT0(); waitForT1(); // Create a new mutex object with the same name and acquire it. There can be a delay between Thread.Join() above // returning and for T0 to abandon its mutex, keep trying to also verify that the mutex object is actually // destroyed and created new again. SpinWait.SpinUntil(() => { using (m = new Mutex(true, mutexName, out bool createdNew)) { if (createdNew) { m.ReleaseMutex(); } return(createdNew); } }); } }
public static void UnregisterEventSignaledWhenUnregistered() { var e0 = new AutoResetEvent(false); var e1 = new AutoResetEvent(false); var registered = ThreadPool.RegisterWaitForSingleObject(e0, (_, __) => {}, null, ThreadTestHelpers.UnexpectedTimeoutMilliseconds, true); registered.Unregister(e1); e1.CheckedWait(); }
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 EventSetAfterUnregisterNotObservedOnWaitThread() { AutoResetEvent e0 = new AutoResetEvent(false); RegisteredWaitHandle handle = ThreadPool.RegisterWaitForSingleObject(e0, (_, __) => {}, null, ThreadTestHelpers.UnexpectedTimeoutMilliseconds, true); handle.Unregister(null); e0.Set(); e0.CheckedWait(); }
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 EventSetAfterUnregisterNotObservedOnWaitThread() { var waitEvent = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, __) => { }, null, UnexpectedTimeoutMilliseconds, true); Assert.True(registeredWaitHandle.Unregister(null)); waitEvent.Set(); Thread.Sleep(ExpectedTimeoutMilliseconds); // give wait thread a chance to observe the signal waitEvent.CheckedWait(); // signal should not have been observed by wait thread }
public static void UnregisterEventSignaledWhenUnregisteredEvenIfAutoUnregistered() { var e0 = new AutoResetEvent(false); RegisteredWaitHandle handle = ThreadPool.RegisterWaitForSingleObject(e0, (_, __) => {}, null, ThreadTestHelpers.UnexpectedTimeoutMilliseconds, true); e0.Set(); Thread.Sleep(50); // Ensure the callback has happened var e1 = new AutoResetEvent(false); handle.Unregister(e1); e1.CheckedWait(); }
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 static void TimingOutRegisteredHandleCallsCallback() { var e0 = new AutoResetEvent(false); var e1 = new AutoResetEvent(false); ThreadPool.RegisterWaitForSingleObject(e0, (_, timedOut) => { if (timedOut) { e1.Set(); } }, null, ThreadTestHelpers.ExpectedTimeoutMilliseconds, true); e1.CheckedWait(); }
public static void StateIsPasssedThroughToCallback() { object state = new object(); AutoResetEvent e0 = new AutoResetEvent(false); ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(true), (callbackState, _) => { if (state == callbackState) { e0.Set(); } }, state, 0, true); e0.CheckedWait(); }
public static void UnregisteringWaitWithEventBeforeSignalingDoesNotCallCallback() { var waitEvent = new AutoResetEvent(false); var waitUnregistered = new AutoResetEvent(false); var waitCallbackInvoked = new AutoResetEvent(false); var registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, __) => { waitCallbackInvoked.Set(); }, null, UnexpectedTimeoutMilliseconds, true); Assert.True(registeredWaitHandle.Unregister(waitUnregistered)); waitUnregistered.CheckedWait(); waitEvent.Set(); Assert.False(waitCallbackInvoked.WaitOne(ExpectedTimeoutMilliseconds)); }
public static void TimingOutRegisteredWaitHandleCallsCallback() { var waitEvent = new AutoResetEvent(false); var waitCallbackInvoked = new AutoResetEvent(false); bool timedOut = false; ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, timedOut2) => { timedOut = timedOut2; waitCallbackInvoked.Set(); }, null, ExpectedTimeoutMilliseconds, true); waitCallbackInvoked.CheckedWait(); Assert.True(timedOut); }
public static void StateIsPassedThroughToCallback() { object state = new object(); var waitCallbackInvoked = new AutoResetEvent(false); object statePassedToCallback = null; ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(true), (callbackState, _) => { statePassedToCallback = callbackState; waitCallbackInvoked.Set(); }, state, 0, true); waitCallbackInvoked.CheckedWait(); Assert.Same(state, statePassedToCallback); }
public static void CallingUnregisterOnAutomaticallyUnregisteredHandleReturnsTrue() { var waitCallbackInvoked = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( new AutoResetEvent(true), (_, __) => waitCallbackInvoked.Set(), null, UnexpectedTimeoutMilliseconds, true); waitCallbackInvoked.CheckedWait(); Thread.Sleep(ExpectedTimeoutMilliseconds); // wait for callback to exit Assert.True(registeredWaitHandle.Unregister(null)); }
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 NonrepeatingWaitFiresOnlyOnce() { var waitEvent = new AutoResetEvent(false); var waitCallbackInvoked = new AutoResetEvent(false); bool anyTimedOut = false; var registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, timedOut) => { anyTimedOut |= timedOut; waitCallbackInvoked.Set(); }, null, UnexpectedTimeoutMilliseconds, true); waitEvent.Set(); waitCallbackInvoked.CheckedWait(); waitEvent.Set(); Assert.False(waitCallbackInvoked.WaitOne(ExpectedTimeoutMilliseconds)); Assert.False(anyTimedOut); }
public static void RepeatingWaitFiresUntilUnregistered() { var e0 = new AutoResetEvent(false); var e1 = new AutoResetEvent(false); var registered = ThreadPool.RegisterWaitForSingleObject(e0, (_, __) => { e1.Set(); }, null, ThreadTestHelpers.UnexpectedTimeoutMilliseconds, false); for (int i = 0; i < 4; ++i) { e0.Set(); e1.CheckedWait(); } registered.Unregister(null); e0.Set(); Assert.False(e1.WaitOne(ThreadTestHelpers.ExpectedTimeoutMilliseconds)); }
public static void StartTest() { var e = new AutoResetEvent(false); Action waitForThread; var t = CreateGuardedThread(out waitForThread, e.CheckedWait); t.IsBackground = true; Assert.Throws <InvalidOperationException>(() => t.Start(null)); Assert.Throws <InvalidOperationException>(() => t.Start(t)); t.Start(); Assert.Throws <ThreadStateException>(() => t.Start()); e.Set(); waitForThread(); Assert.Throws <ThreadStateException>(() => t.Start()); t = CreateGuardedThread(out waitForThread, parameter => e.CheckedWait()); t.IsBackground = true; t.Start(); Assert.Throws <ThreadStateException>(() => t.Start()); Assert.Throws <ThreadStateException>(() => t.Start(null)); Assert.Throws <ThreadStateException>(() => t.Start(t)); e.Set(); waitForThread(); Assert.Throws <ThreadStateException>(() => t.Start()); Assert.Throws <ThreadStateException>(() => t.Start(null)); Assert.Throws <ThreadStateException>(() => t.Start(t)); t = CreateGuardedThread(out waitForThread, parameter => Assert.Null(parameter)); t.IsBackground = true; t.Start(); waitForThread(); t = CreateGuardedThread(out waitForThread, parameter => Assert.Null(parameter)); t.IsBackground = true; t.Start(null); waitForThread(); t = CreateGuardedThread(out waitForThread, parameter => Assert.Equal(t, parameter)); t.IsBackground = true; t.Start(t); waitForThread(); }
public static void MultipleRegisteredWaitsUnregisterHandleShiftTest() { var handlePendingRemoval = new AutoResetEvent(false); var completeWaitCallback = new AutoResetEvent(false); WaitOrTimerCallback waitCallback = (_, __) => { handlePendingRemoval.Set(); completeWaitCallback.CheckedWait(); }; var waitEvent = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, waitCallback, null, UnexpectedTimeoutMilliseconds, true); var waitEvent2 = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle2 = ThreadPool.RegisterWaitForSingleObject(waitEvent2, waitCallback, null, UnexpectedTimeoutMilliseconds, true); var waitEvent3 = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle3 = ThreadPool.RegisterWaitForSingleObject(waitEvent3, waitCallback, null, UnexpectedTimeoutMilliseconds, true); void SetAndUnregister(AutoResetEvent waitEvent, RegisteredWaitHandle registeredWaitHandle) { waitEvent.Set(); handlePendingRemoval.CheckedWait(); Thread.Sleep(ExpectedTimeoutMilliseconds); // wait for removal Assert.True(registeredWaitHandle.Unregister(null)); completeWaitCallback.Set(); waitEvent.Dispose(); } SetAndUnregister(waitEvent, registeredWaitHandle); SetAndUnregister(waitEvent2, registeredWaitHandle2); var waitEvent4 = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle4 = ThreadPool.RegisterWaitForSingleObject(waitEvent4, waitCallback, null, UnexpectedTimeoutMilliseconds, true); SetAndUnregister(waitEvent3, registeredWaitHandle3); SetAndUnregister(waitEvent4, registeredWaitHandle4); }
public static void RepeatingWaitFiresUntilUnregistered() { var waitEvent = new AutoResetEvent(false); var waitCallbackInvoked = new AutoResetEvent(false); bool anyTimedOut = false; var registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitEvent, (_, timedOut) => { anyTimedOut |= timedOut; waitCallbackInvoked.Set(); }, null, UnexpectedTimeoutMilliseconds, false); for (int i = 0; i < 4; ++i) { waitEvent.Set(); waitCallbackInvoked.CheckedWait(); } Assert.True(registeredWaitHandle.Unregister(new InvalidWaitHandle())); // blocking unregister waitEvent.Set(); Assert.False(waitCallbackInvoked.WaitOne(ExpectedTimeoutMilliseconds)); Assert.False(anyTimedOut); }
public void MutualExclusionTest() { var threadLocked = new AutoResetEvent(false); var continueThread = new AutoResetEvent(false); var m = new Mutex(); Thread t = ThreadTestHelpers.CreateGuardedThread(out Action waitForThread, () => { Assert.True(m.WaitOne(0)); threadLocked.Set(); continueThread.CheckedWait(); m.ReleaseMutex(); }); t.IsBackground = true; t.Start(); threadLocked.CheckedWait(); Assert.False(m.WaitOne(0)); Assert.False(m.WaitOne(ThreadTestHelpers.ExpectedTimeoutMilliseconds)); continueThread.Set(); waitForThread(); Assert.True(m.WaitOne(0)); m.ReleaseMutex(); }
public static void InterruptInFinallyBlockTest_SkipOnDesktopFramework() { // A wait in a finally block can be interrupted. The desktop framework applies the same rules as thread abort, and // does not allow thread interrupt in a finally block. There is nothing special about thread interrupt that requires // not allowing it in finally blocks, so this behavior has changed in .NET Core. var continueThread = new AutoResetEvent(false); Action waitForThread; Thread t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => { try { } finally { Assert.Throws <ThreadInterruptedException>(() => continueThread.CheckedWait()); } }); t.IsBackground = true; t.Start(); t.Interrupt(); waitForThread(); }
public static void ReadersWaitingOnWaitingWriterTest() { var trwl = new TestReaderWriterLock(); trwl.AcquireReaderLock(); var waitingWriterReady = new AutoResetEvent(false); var continueWaitingWriter = new AutoResetEvent(false); Action waitForWaitingWriter; Thread waitingWriter = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingWriter, () => { trwl.AcquireWriterLock(); waitingWriterReady.Set(); continueWaitingWriter.CheckedWait(); trwl.ReleaseWriterLock(); }); waitingWriter.IsBackground = true; waitingWriter.Start(); ThreadTestHelpers.WaitForCondition(() => (waitingWriter.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 writer trwl.ReleaseReaderLock(); waitingWriterReady.CheckedWait(); // Releasing the now-writer's write lock releases all waiting readers continueWaitingWriter.Set(); waitForWaitingWriter(); waitForWaitingReader1(); waitForWaitingReader2(); trwl.Dispose(); }
public static void InterruptTest() { // Interrupting a thread that is not blocked does not do anything, but once the thread starts blocking, it gets // interrupted var threadReady = new AutoResetEvent(false); var continueThread = new AutoResetEvent(false); bool continueThreadBool = false; Action waitForThread; var t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => { threadReady.Set(); ThreadTestHelpers.WaitForConditionWithoutBlocking(() => Volatile.Read(ref continueThreadBool)); threadReady.Set(); Assert.Throws<ThreadInterruptedException>(() => continueThread.CheckedWait()); }); t.IsBackground = true; t.Start(); threadReady.CheckedWait(); t.Interrupt(); Assert.False(threadReady.WaitOne(ExpectedTimeoutMilliseconds)); Volatile.Write(ref continueThreadBool, true); waitForThread(); // Interrupting a dead thread does nothing t.Interrupt(); // Interrupting an unstarted thread causes the thread to be interrupted after it is started and starts blocking t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => Assert.Throws<ThreadInterruptedException>(() => continueThread.CheckedWait())); t.IsBackground = true; t.Interrupt(); t.Start(); waitForThread(); // A thread that is already blocked on a synchronization primitive unblocks immediately continueThread.Reset(); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () => Assert.Throws<ThreadInterruptedException>(() => continueThread.CheckedWait())); t.IsBackground = true; t.Start(); ThreadTestHelpers.WaitForCondition(() => (t.ThreadState & ThreadState.WaitSleepJoin) != 0); t.Interrupt(); waitForThread(); }
public static void StartTest() { var e = new AutoResetEvent(false); Action waitForThread; var t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, e.CheckedWait); t.IsBackground = true; Assert.Throws<InvalidOperationException>(() => t.Start(null)); Assert.Throws<InvalidOperationException>(() => t.Start(t)); t.Start(); Assert.Throws<ThreadStateException>(() => t.Start()); e.Set(); waitForThread(); Assert.Throws<ThreadStateException>(() => t.Start()); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => e.CheckedWait()); t.IsBackground = true; t.Start(); Assert.Throws<ThreadStateException>(() => t.Start()); Assert.Throws<ThreadStateException>(() => t.Start(null)); Assert.Throws<ThreadStateException>(() => t.Start(t)); e.Set(); waitForThread(); Assert.Throws<ThreadStateException>(() => t.Start()); Assert.Throws<ThreadStateException>(() => t.Start(null)); Assert.Throws<ThreadStateException>(() => t.Start(t)); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => Assert.Null(parameter)); t.IsBackground = true; t.Start(); waitForThread(); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => Assert.Null(parameter)); t.IsBackground = true; t.Start(null); waitForThread(); t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => Assert.Equal(t, parameter)); t.IsBackground = true; t.Start(t); 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 QueueRegisterPositiveAndFlowTest() { var asyncLocal = new AsyncLocal<int>(); asyncLocal.Value = 1; var obj = new object(); var registerWaitEvent = new AutoResetEvent(false); var threadDone = new AutoResetEvent(false); RegisteredWaitHandle registeredWaitHandle = null; Exception backgroundEx = null; int backgroundAsyncLocalValue = 0; Action<bool, Action> commonBackgroundTest = (isRegisteredWaitCallback, test) => { try { if (isRegisteredWaitCallback) { RegisteredWaitHandle toUnregister = registeredWaitHandle; registeredWaitHandle = null; Assert.True(toUnregister.Unregister(threadDone)); } test(); backgroundAsyncLocalValue = asyncLocal.Value; } catch (Exception ex) { backgroundEx = ex; } finally { if (!isRegisteredWaitCallback) { threadDone.Set(); } } }; Action<bool> waitForBackgroundWork = isWaitForRegisteredWaitCallback => { if (isWaitForRegisteredWaitCallback) { registerWaitEvent.Set(); } threadDone.CheckedWait(); if (backgroundEx != null) { throw new AggregateException(backgroundEx); } }; ThreadPool.QueueUserWorkItem( state => { commonBackgroundTest(false, () => { Assert.Same(obj, state); }); }, obj); waitForBackgroundWork(false); Assert.Equal(1, backgroundAsyncLocalValue); ThreadPool.UnsafeQueueUserWorkItem( state => { commonBackgroundTest(false, () => { Assert.Same(obj, state); }); }, obj); waitForBackgroundWork(false); Assert.Equal(0, backgroundAsyncLocalValue); registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( registerWaitEvent, (state, timedOut) => { commonBackgroundTest(true, () => { Assert.Same(obj, state); Assert.False(timedOut); }); }, obj, UnexpectedTimeoutMilliseconds, false); waitForBackgroundWork(true); Assert.Equal(1, backgroundAsyncLocalValue); registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject( registerWaitEvent, (state, timedOut) => { commonBackgroundTest(true, () => { Assert.Same(obj, state); Assert.False(timedOut); }); }, obj, UnexpectedTimeoutMilliseconds, false); waitForBackgroundWork(true); Assert.Equal(0, backgroundAsyncLocalValue); }
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(); }); }