コード例 #1
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenReadLockReleased_ReleasesAWaitingWriterIfPresent()
        {
            const int        initialValue      = 10;
            const int        successValue      = 25;
            int              writeResult       = initialValue;
            ManualResetEvent writerExitedEvent = new ManualResetEvent(false);

            Locksmith.EnterReadLock(ref lockState, readLockTestObject);
            {
                StartNewThreadThatRuns(SetWriteResultToFailureValue);
                Thread.Sleep(50);
                Assert.That(WritersAreWaiting);
                Assert.That(writeResult, Is.EqualTo(initialValue));
            }
            Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

            writerExitedEvent.WaitOne();
            Assert.That(writeResult, Is.EqualTo(successValue));

            return;


            void SetWriteResultToFailureValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                {
                    writeResult = successValue;
                }
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

                writerExitedEvent.Set();
            }
        }
コード例 #2
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenWriteLockReleased_ReleasesAllWaitingReaders()
        {
            int            numberOfThreadsToCreate = 100;
            int            numberOfReads           = 0;
            CountdownEvent readersExitedEvent      = new CountdownEvent(numberOfThreadsToCreate);

            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
            {
                for (int i = 0; i < numberOfThreadsToCreate; i++)
                {
                    StartNewThreadThatRuns(IncrementNumReadsInsideReadLock);
                }

                Thread.Sleep(1000);
                Assert.That(numberOfReads, Is.EqualTo(0));
            }
            Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

            readersExitedEvent.Wait();
            Assert.That(numberOfReads, Is.EqualTo(numberOfThreadsToCreate));

            return;


            void IncrementNumReadsInsideReadLock()
            {
                Locksmith.EnterReadLock(ref lockState, readLockTestObject);
                {
                    Interlocked.Increment(ref numberOfReads);
                }
                Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

                readersExitedEvent.Signal();
            }
        }
コード例 #3
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenWriteLockReleased_ReleasesAWaitingReaderIfPresent()
        {
            const int        initialValue      = 10;
            const int        expectedValue     = 42;
            int              readResult        = initialValue;
            ManualResetEvent readerExitedEvent = new ManualResetEvent(false);

            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
            {
                StartNewThreadThatRuns(SetReadResultToExpectedValue);
                Thread.Sleep(100);
                Assert.That(ReadersAreWaiting);
                Assert.That(readResult, Is.EqualTo(initialValue));
            }
            Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

            //- This should be more than enough time for the other thread to wake up and set the value.
            readerExitedEvent.WaitOne();
            Assert.That(readResult, Is.EqualTo(expectedValue));

            return;


            void SetReadResultToExpectedValue()
            {
                Locksmith.EnterReadLock(ref lockState, readLockTestObject);
                {
                    readResult = expectedValue;
                }
                Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

                readerExitedEvent.Set();
            }
        }
コード例 #4
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        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);
            }
        }
コード例 #5
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenReadLockedAndReservedForWriter_CausesNewReadersToWait()
        {
            const int      initialValue       = 10;
            const int      valueAddedByReader = 50;
            const int      valueAddedByWriter = 20;
            int            result             = initialValue;
            CountdownEvent exitedLocksEvent   = new CountdownEvent(2);

            Locksmith.EnterReadLock(ref lockState, readLockTestObject);
            {
                StartNewThreadThatRuns(AddWriterValue);
                Thread.Sleep(300);
                StartNewThreadThatRuns(AddReaderValue);
                Thread.Sleep(300);
                Assert.That(result, Is.EqualTo(initialValue));
                Assert.That(lockState.IsReservedForWriter());
                Assert.That(lockState.HasWaitingReaders());
            }
            Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

            exitedLocksEvent.Wait();

            return;

            void AddReaderValue()
            {
                Locksmith.EnterReadLock(ref lockState, readLockTestObject);  //- You passed the wrong object ya dolt...
                {
                    int currentResult;
                    int valueToSet;

                    do
                    {
                        currentResult = result;
                        valueToSet    = currentResult + valueAddedByReader;
                    } while (Interlocked.CompareExchange(ref result, valueToSet, currentResult) != currentResult);
                }
                Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

                exitedLocksEvent.Signal();
            }

            void AddWriterValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                {
                    int currentResult, valueToSet;

                    do
                    {
                        currentResult = result;
                        valueToSet    = currentResult + valueAddedByWriter;
                    }while (Interlocked.CompareExchange(ref result, valueToSet, currentResult) != currentResult);
                }
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

                exitedLocksEvent.Signal();
            }
        }
コード例 #6
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
 public void Locksmith_WhileUnlocked_AllowsAWriterToEnter()
 {
     Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
     {
         Thread.SpinWait(1);
     }
     Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
 }
コード例 #7
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenWriteLocked_ThrowsIfExitReadLockIsCalled()
        {
            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
            Assert.Throws <SynchronizationLockException>(ExitLockWithExitReadLock);
            Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

            return;


            void ExitLockWithExitReadLock() =>
            Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);
        }
コード例 #8
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        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);
        }
コード例 #9
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        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();
            }
        }
コード例 #10
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenReadLockReleased_ReleasesOnlyOneWaitingWriter()
        {
            const int        initialValue      = 10;
            const int        valueToAdd        = 15;
            const int        successValue      = initialValue + valueToAdd;
            int              result            = initialValue;
            ManualResetEvent resultTestedEvent = new ManualResetEvent(false);

            Locksmith.EnterReadLock(ref lockState, readLockTestObject);
            {
                StartNewThreadThatRuns(SetWriteResultToFailureValue);
                StartNewThreadThatRuns(SetWriteResultToFailureValue);
                Thread.Sleep(300);
                Assert.That(NumberOfWaitingWriters, Is.EqualTo(2));
                Assert.That(result, Is.EqualTo(initialValue));
            }
            Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

            Thread.Sleep(500);
            Assert.That(result, Is.EqualTo(successValue));
            resultTestedEvent.Set();

            return;


            void SetWriteResultToFailureValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                {
                    int currentResult;
                    int valueToSet;

                    do
                    {
                        currentResult = result;
                        valueToSet    = currentResult + valueToAdd;
                    }while (Interlocked.CompareExchange(ref result, valueToSet, currentResult) != currentResult);

                    resultTestedEvent.WaitOne();
                }
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
            }
        }
コード例 #11
0
        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);
        }
コード例 #12
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenAReaderHasDecidedToWait_WillNotDeadlockIfTheReaderCantCallWaitBeforeAWriterExits()
        {
            const int        initialValue      = 10;
            const int        expectedValue     = 42;
            int              valueBeingTested  = initialValue;
            ManualResetEvent readerExitedEvent = new ManualResetEvent(false);

            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);

            lock (readLockTestObject)  //- This should prevent the reader from being able to lock the same object, which it needs to do in order to call Monitor.Wait()
            {
                StartNewThreadThatRuns(SetReadResultToTestInt);
                //- Hold the lock long enough that the reader will decide to start waiting
                Thread.Sleep(500);
                Assert.That(ReadersAreWaiting);
                //- Make sure they didn't manage to set the value despite the lock somehow.
                Assert.That(valueBeingTested, Is.EqualTo(initialValue));
                //- Exit the write lock, which should call Monitor.PulseAll().
                //  lock() is re-entrant so the fact that we already locked the read lock object,
                //  shouldn't prevent this thread from reacquiring the lock to call Monitor.PulseAll().
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
            }

            //- Give the reader time to work if they managed to avoid the deadlock
            readerExitedEvent.WaitOne();
            Assert.That(valueBeingTested, Is.EqualTo(expectedValue));

            return;


            void SetReadResultToTestInt()
            {
                Locksmith.EnterReadLock(ref lockState, readLockTestObject);
                {
                    valueBeingTested = expectedValue;
                }
                Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

                readerExitedEvent.Set();
            }
        }
コード例 #13
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhileWriteLocked_PreventsOtherWritersFromEntering()
        {
            const int initialValue     = 10;
            const int expectedValue    = 42;
            int       valueBeingTested = initialValue;

            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
            {
                StartNewThreadThatRuns(SetValueBeingTestedToExpectedValue);
                Thread.Sleep(1000);
                Assert.That(valueBeingTested, Is.EqualTo(initialValue));
            }
            Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

            void SetValueBeingTestedToExpectedValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                valueBeingTested = expectedValue;
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
            }
        }
コード例 #14
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhileReadLocked_PreventsWritersFromEntering()
        {
            const int failureValue  = 25;
            const int expectedValue = 10;
            int       writeResult   = expectedValue;

            Locksmith.EnterReadLock(ref lockState, readLockTestObject);
            {
                StartNewThreadThatRuns(SetWriteResultToFailureValue);
                Thread.Sleep(1000);
                Assert.That(writeResult, Is.EqualTo(expectedValue));
            }
            Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);

            return;


            void SetWriteResultToFailureValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                writeResult = failureValue;
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
            }
        }
コード例 #15
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenWriteLockReleased_ReleasesAWaitingWriterIfPresent()
        {
            const int        initialValue      = 10;
            const int        expectedValue     = 42;
            int              valueBeingTested  = initialValue;
            ManualResetEvent writerExitedEvent = new ManualResetEvent(false);


            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
            {
                StartNewThreadThatRuns(SetValueBeingTestedToExpectedValue);
                //- We'll wait a while to give the other thread a chance to set the value, so we can see if the lock works.
                Thread.Sleep(100);
                Assert.That(WritersAreWaiting);
                Assert.That(valueBeingTested, Is.EqualTo(initialValue));
            }
            Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

            //- This should be more than enough time for the other thread to wake up and set the value.
            writerExitedEvent.WaitOne();
            Assert.That(valueBeingTested, Is.EqualTo(expectedValue));

            return;


            void SetValueBeingTestedToExpectedValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                {
                    valueBeingTested = expectedValue;
                }
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

                writerExitedEvent.Set();
            }
        }
コード例 #16
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        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);
            }
        }
コード例 #17
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
 void SetIntToValueInsideWriteLock(ref int intToSet, int valueToSetTo)
 {
     Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
     intToSet = valueToSetTo;
     Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
 }
コード例 #18
0
ファイル: LocksmithTests.cs プロジェクト: Dextarius/Locksmith
        public void Locksmith_WhenWriteLockReleased_ReleasesWaitingWritersBeforeWaitingReaders()
        {
            const int        initialValue       = 10;
            const int        valueAddedByReader = 50;
            const int        valueAddedByWriter = 20;
            const int        successValue       = initialValue + valueAddedByWriter;
            int              result             = initialValue;
            ManualResetEvent valueSetEvent      = new ManualResetEvent(false);
            ManualResetEvent valueTestedEvent   = new ManualResetEvent(false);

            Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
            {
                StartNewThreadThatRuns(AddWriterValue);
                Thread.Sleep(200);
                Assert.That(WritersAreWaiting);
                StartNewThreadThatRuns(AddReaderValue);
                Thread.Sleep(200);
                Assert.That(ReadersAreWaiting);
                Assert.That(result, Is.EqualTo(initialValue));
            }
            Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);

            valueSetEvent.WaitOne();
            Assert.That(ReadersAreWaiting);
            Assert.That(WritersAreWaiting == false);
            Assert.That(result, Is.EqualTo(successValue));
            valueTestedEvent.Set();

            return;


            void AddReaderValue()
            {
                Locksmith.EnterReadLock(ref lockState, readLockTestObject);
                {
                    int currentResult, valueToSet;

                    do
                    {
                        currentResult = result;
                        valueToSet    = currentResult + valueAddedByReader;
                    } while (Interlocked.CompareExchange(ref result, valueToSet, currentResult) != currentResult);
                }
                Locksmith.ExitReadLock(ref lockState, readLockTestObject, writeLockTestObject);
            }

            void AddWriterValue()
            {
                Locksmith.EnterWriteLock(ref lockState, writeLockTestObject);
                {
                    int currentResult;
                    int valueToSet;

                    do
                    {
                        currentResult = result;
                        valueToSet    = currentResult + valueAddedByWriter;
                    }while (Interlocked.CompareExchange(ref result, valueToSet, currentResult) != currentResult);

                    valueSetEvent.Set();
                    valueTestedEvent.WaitOne();
                }
                Locksmith.ExitWriteLock(ref lockState, readLockTestObject, writeLockTestObject);
            }
        }