public static void InvalidLockCookieTest() { // Invalid lock cookie created by using one up with Upgrade/Downgrade var trwl = new TestReaderWriterLock(); TestLockCookie tlc = trwl.UpgradeToWriterLock(); trwl.DowngradeFromWriterLock(tlc); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult); // Invalid lock cookie created by using one up with Release/Restore tlc = trwl.ReleaseLock(); trwl.RestoreLock(tlc); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult); // Lock cookie owned by another thread ThreadTestHelpers.RunTestInBackgroundThread(() => { TestLockCookie tlc2 = trwl.UpgradeToWriterLock(); tlc = tlc2.Clone(); trwl.DowngradeFromWriterLock(tlc2); }); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult); trwl.Dispose(); }
public void DowngradeFromWriterLock(TestLockCookie tlc, int expectedFailureHResult = 0) { Assert.NotNull(tlc); PerformLockAction( expectedFailureHResult, false /* isBlockingOperation */, () => _rwl.DowngradeFromWriterLock(ref tlc._lockCookie), () => { Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID); Assert.NotEqual(0, _writerLevel); if (tlc._readerLevel == 0) { Assert.True(_writerLevel > tlc._writerLevel); _writerLevel = tlc._writerLevel; if (_writerLevel == 0) { _writerThreadID = InvalidThreadID; } } else { _writerLevel = 0; _writerThreadID = InvalidThreadID; Assert.True(ThreadReaderLevel == 0); ThreadReaderLevel = tlc._readerLevel; } }); }
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 ShouldNotBeOwnerForRestoreLockTest() { var trwl = new TestReaderWriterLock(); trwl.AcquireReaderLock(); TestLockCookie restoreReadLockTlc = trwl.ReleaseLock(); trwl.AcquireWriterLock(); TestLockCookie restoreWriteLockTlc = trwl.ReleaseLock(); Action verifyCannotRestore = () => { Assert.Throws <SynchronizationLockException>(() => trwl.RestoreLock(restoreReadLockTlc)); Assert.Throws <SynchronizationLockException>(() => trwl.RestoreLock(restoreWriteLockTlc)); }; trwl.AcquireReaderLock(); verifyCannotRestore(); trwl.ReleaseReaderLock(); trwl.AcquireWriterLock(); verifyCannotRestore(); trwl.ReleaseWriterLock(); trwl.Dispose(); }
public TestLockCookie ReleaseLock() { TestLockCookie tlc = null; LockCookie lockCookie = default(LockCookie); PerformLockAction( 0 /* expectedFailureHResult */, false /* isBlockingOperation */, () => lockCookie = _rwl.ReleaseLock(), () => { tlc = new TestLockCookie() { _lockCookie = lockCookie, _readerLevel = ThreadReaderLevel, _writerLevel = _writerLevel }; if (_writerLevel != 0) { Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID); } ThreadReaderLevel = 0; _writerLevel = 0; _writerThreadID = InvalidThreadID; }); return(tlc); }
public TestLockCookie UpgradeToWriterLock(int expectedFailureHResult = 0) { TestLockCookie tlc = null; LockCookie lockCookie = default(LockCookie); PerformLockAction( expectedFailureHResult, true /* isBlockingOperation */, () => lockCookie = _rwl.UpgradeToWriterLock(GetTimeoutMilliseconds(expectedFailureHResult)), () => { tlc = new TestLockCookie() { _lockCookie = lockCookie, _readerLevel = ThreadReaderLevel, _writerLevel = _writerLevel }; ThreadReaderLevel = 0; if (_writerLevel == 0) { Assert.Equal(InvalidThreadID, _writerThreadID); _writerThreadID = Environment.CurrentManagedThreadId; ++_writerSeqNum; } else { Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID); } ++_writerLevel; }); return(tlc); }
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 static void NotOwnerTest() { var trwl = new TestReaderWriterLock(); trwl.ReleaseReaderLock(NotOwnerExceptionHResult); trwl.ReleaseWriterLock(NotOwnerExceptionHResult); trwl.DowngradeFromWriterLock(new TestLockCookie(), NotOwnerExceptionHResult); { trwl.AcquireReaderLock(); trwl.ReleaseWriterLock(NotOwnerExceptionHResult); TestLockCookie tlc = trwl.UpgradeToWriterLock(); TestLockCookie tlc2 = tlc.Clone(); trwl.DowngradeFromWriterLock(tlc); // tlc is invalid, tlc2 is valid trwl.DowngradeFromWriterLock(tlc2, NotOwnerExceptionHResult); trwl.ReleaseReaderLock(); } trwl.Dispose(); }
public void RestoreLock(TestLockCookie tlc, int expectedFailureHResult = 0) { Assert.NotNull(tlc); Assert.NotEqual(TimeoutExceptionHResult, expectedFailureHResult); PerformLockAction( expectedFailureHResult, true /* isBlockingOperation */, () => _rwl.RestoreLock(ref tlc._lockCookie), () => { Assert.Equal(0, ThreadReaderLevel); Assert.Equal(InvalidThreadID, _writerThreadID); Assert.Equal(0, _writerLevel); ThreadReaderLevel = tlc._readerLevel; _writerLevel = tlc._writerLevel; if (_writerLevel != 0) { Assert.Equal(InvalidThreadID, _writerThreadID); _writerThreadID = Environment.CurrentManagedThreadId; ++_writerSeqNum; } }); }
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 TestLockCookie ReleaseLock() { TestLockCookie tlc = null; LockCookie lockCookie = default(LockCookie); PerformLockAction( 0 /* expectedFailureHResult */, false /* isBlockingOperation */, () => lockCookie = _rwl.ReleaseLock(), () => { tlc = new TestLockCookie() { _lockCookie = lockCookie, _readerLevel = ThreadReaderLevel, _writerLevel = _writerLevel }; if (_writerLevel != 0) { Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID); } ThreadReaderLevel = 0; _writerLevel = 0; _writerThreadID = InvalidThreadID; }); return tlc; }
public TestLockCookie UpgradeToWriterLock(int expectedFailureHResult = 0) { TestLockCookie tlc = null; LockCookie lockCookie = default(LockCookie); PerformLockAction( expectedFailureHResult, true /* isBlockingOperation */, () => lockCookie = _rwl.UpgradeToWriterLock(GetTimeoutMilliseconds(expectedFailureHResult)), () => { tlc = new TestLockCookie() { _lockCookie = lockCookie, _readerLevel = ThreadReaderLevel, _writerLevel = _writerLevel }; ThreadReaderLevel = 0; if (_writerLevel == 0) { Assert.Equal(InvalidThreadID, _writerThreadID); _writerThreadID = Environment.CurrentManagedThreadId; ++_writerSeqNum; } else { Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID); } ++_writerLevel; }); return tlc; }