public void Locksmith_WhenReadLockIsUpgradedWithOnlyOneReader_PreventsNewReadersFromEntering() { const int failureValue = 25; const int expectedValue = 10; int result = expectedValue; Locksmith.EnterReadLock(ref lockState, readLockTestObject); Locksmith.Upgrade(ref lockState, writeLockTestObject); { StartNewThreadThatRuns(SetReadResultToFailureValue); Thread.Sleep(1000); Assert.That(result, Is.EqualTo(expectedValue)); } Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject); return; void SetReadResultToFailureValue() { Locksmith.EnterReadLock(ref lockState, readLockTestObject); result = failureValue; Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject); } }
public void Locksmith_WhenReadLockIsUpgraded_ThrowsIfExitReadLockIsCalled() { Locksmith.EnterReadLock(ref lockState, readLockTestObject); Locksmith.Upgrade(ref lockState, writeLockTestObject); Assert.Throws <SynchronizationLockException>(TryToCallExitReadLock); Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject); return; void TryToCallExitReadLock() => Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject); }
public void Locksmith_WhenReadLockIsUpgradedWhileOtherReadersAreActive_WaitsUntilAllOtherReadersExitToConvertLock() { const int numberOfOtherReaders = 10; int numberOfReads = 0; int numberOfExits = 0; CountdownEvent readEvent = new CountdownEvent(numberOfOtherReaders); CountdownEvent exitEvent = new CountdownEvent(numberOfOtherReaders); ManualResetEvent upgradeEvent = new ManualResetEvent(false); Locksmith.EnterReadLock(ref lockState, readLockTestObject); for (int i = 0; i < numberOfOtherReaders; i++) { StartNewThreadThatRuns(IncrementNumReadsInsideReadLock); } readEvent.Wait(); Assert.That(numberOfReads, Is.EqualTo(numberOfOtherReaders)); upgradeEvent.Set(); Locksmith.Upgrade(ref lockState, writeLockTestObject); { Assert.That(lockState.IsReadLocked() == false, $"{lockState}"); exitEvent.Wait(); Assert.That(numberOfExits, Is.EqualTo(numberOfOtherReaders)); } Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject); return; void IncrementNumReadsInsideReadLock() { Locksmith.EnterReadLock(ref lockState, readLockTestObject); { Interlocked.Increment(ref numberOfReads); readEvent.Signal(); upgradeEvent.WaitOne(); Thread.Sleep(1000); Assert.That(ReservedForUpgrade && IsReadLocked); } Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject); Interlocked.Increment(ref numberOfExits); exitEvent.Signal(); } }
public bool IfValueEqualsFirstSetToSecond(T valueToTestFor, T valueToSetTo) { Locksmith.EnterReadLock(ref lockState, readLockobject); { if (lockedValue.Equals(valueToTestFor)) { Locksmith.Upgrade(ref lockState, this); { lockedValue = valueToSetTo; } Locksmith.ExitWriteLock(ref lockState, readLockobject, this); return(true); } } Locksmith.ExitReadLock(ref lockState, readLockobject, this); return(false); }
public void Locksmith_WhenReadLockIsUpgradedWhileOtherReadersAreActive_PreventsNewReadersFromEntering() { const int numberOfOtherReaders = 10; int numberOfReadersEntered = 0; int numberOfExits = 0; CountdownEvent readEvent = new CountdownEvent(numberOfOtherReaders); CountdownEvent exitEvent = new CountdownEvent(numberOfOtherReaders); ManualResetEvent outerUpgradeEvent = new ManualResetEvent(false); ManualResetEvent innerUpgradeEvent = new ManualResetEvent(false); for (int i = 0; i < numberOfOtherReaders; i++) { StartNewThreadThatRuns(IncrementNumReadsInsideReadLock_FirstSet); } readEvent.Wait(); Assert.That(numberOfReadersEntered, Is.EqualTo(numberOfOtherReaders)); StartNewThreadThatRuns(EnterReadLockAndUpgrade); exitEvent.Wait(); Assert.That(numberOfExits, Is.EqualTo(numberOfOtherReaders)); for (int i = 0; i < numberOfOtherReaders; i++) { StartNewThreadThatRuns(IncrementNumReadsInsideReadLock_SecondSet); } Thread.Sleep(1000); Assert.That(numberOfReadersEntered, Is.EqualTo(numberOfOtherReaders)); innerUpgradeEvent.Set(); return; void EnterReadLockAndUpgrade() { Locksmith.EnterReadLock(ref lockState, readLockTestObject); outerUpgradeEvent.Set(); Locksmith.Upgrade(ref lockState, writeLockTestObject); { innerUpgradeEvent.WaitOne(); Assert.That(numberOfExits, Is.EqualTo(numberOfOtherReaders)); } Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject); } void IncrementNumReadsInsideReadLock_FirstSet() { Locksmith.EnterReadLock(ref lockState, readLockTestObject); { Interlocked.Increment(ref numberOfReadersEntered); readEvent.Signal(); outerUpgradeEvent.WaitOne(); Thread.Sleep(1000); } Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject); Interlocked.Increment(ref numberOfExits); exitEvent.Signal(); } void IncrementNumReadsInsideReadLock_SecondSet() { Locksmith.EnterReadLock(ref lockState, readLockTestObject); { Interlocked.Increment(ref numberOfReadersEntered); } Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject); Interlocked.Increment(ref numberOfExits); } }