public override void RunTest(ISyncLock lockObject, TestParameters testParameters) { if (lockObject is NoOpLock) { throw new InapplicableTestException("Unbalanced calls test not applicable for this lock type"); } Console.WriteLine("Normal usage scenario -- autolock create / dispose with using"); ExerciseStandardUsage(lockObject, false); Console.WriteLine("Normal usage scenario -- succeeded"); Console.WriteLine("Exception in using -- lock should be freed"); try { ExerciseStandardUsage(lockObject, true); } catch (IntentionalTestException e) { Console.WriteLine("Expected exception caught: {0}: {1}", e.GetType().ToString(), e.Message); } Console.WriteLine("Validate that the lock is freed by exercising the normal scenario again"); ExerciseStandardUsage(lockObject, false); }
public override void RunTest(ISyncLock syncLock, TestParameters testParameters) { this.syncLock = (ISyncLock)syncLock; requireLock = !(syncLock is NoOpLock); testTimeoutSeconds = testParameters.MaxWaitSeconds; Thread[] threads = new Thread[desiredValues.Length]; for (int threadIndex = 0; threadIndex < threads.Length; threadIndex++) { threads[threadIndex] = new Thread(ContendingThreadFunction); completedEvents[threadIndex] = new ManualResetEvent(false); threads[threadIndex].Start(threadIndex); } startThreadsEvent.Set(); Console.WriteLine("Sleeping for {0} seconds", testParameters.MaxWaitSeconds); Thread.Sleep(testParameters.MaxWaitSeconds * 1000); Console.WriteLine("Signaling threads to terminate"); endTestEvent.Set(); Console.WriteLine("Waiting for {0} threads to complete after termination signal", threads.Length); WaitHandle.WaitAll(completedEvents); Console.WriteLine("Completed all waits for thread ids:"); for (int threadIndex = 0; threadIndex < threads.Length; threadIndex++) { Console.WriteLine("Thread: {0}\tIterations: {1}", threads[threadIndex].ManagedThreadId, iterationCounts[threadIndex]); } if (!requireLock) { if (!expectedSynchronizationErrorOccurred) { throw new InvalidOperationException("Expected synchronization error due to absence of lock did not occur."); } Console.WriteLine("Expected synchronization error successfully detected."); } else if (null != testException) { throw testException; } }
void ExerciseStandardUsage(ISyncLock lockObject, bool throwException) { using (AutoLock.Lock(lockObject)) { Console.WriteLine("Inside autolock block"); if (throwException) { Console.WriteLine("Testing exception thrown in autolock block -- will now throw exception"); throw new IntentionalTestException("Intentional exception thrown inside of an autolock block"); } } InvalidOperationException unlockException = null; Console.WriteLine("Validate that the lock is correctly unlocked after exiting using block"); try { lockObject.Unlock(); } catch (InvalidOperationException e) { unlockException = e; } if (unlockException != null) { Console.WriteLine("Caught expected exception from unlocking an unlocked object"); } else { throw new InvalidOperationException("Failed to get exception in unlocking unlocked object after an autolock was exited"); } }
public override void RunTest(ISyncLock lockObject, TestParameters testParameters) { if (lockObject is NoOpLock) { throw new InapplicableTestException("Unbalanced calls test not applicable for this lock type"); } ISyncLock syncLock = (ISyncLock)lockObject; Exception releaseUnlockedException = null; Console.WriteLine("Trying unlock with no lock -- this should fail"); try { syncLock.Unlock(); } catch (InvalidOperationException e) { Console.WriteLine("Caught expected InvalidOperationException"); releaseUnlockedException = e; } Console.WriteLine("Lock / unlock succeeded"); if (releaseUnlockedException == null) { throw new InvalidOperationException("Unlock of already unlocked lock should not have succeeded"); } Console.WriteLine("Simple lock / unlock -- this should succeed"); syncLock.Lock(); syncLock.Unlock(); Console.WriteLine("Re-entrant lock scenario -- try locking twice -- this should fail for some locks, succeed for others"); Exception reentrantLockException = null; syncLock.Lock(); try { Console.WriteLine("Second lock attempt"); syncLock.Lock(); Console.WriteLine("Second lock granted"); } catch (InvalidOperationException e) { Console.WriteLine("Expected InvalidOperationException caught"); reentrantLockException = e; } syncLock.Unlock(); if (syncLock.GetType() == typeof(SimpleSpinLock)) { if (reentrantLockException == null) { throw new InvalidOperationException("Lock should not allow re-entrant call to already locked lock"); } } else { Console.WriteLine("Successful re-entrant lock with lock count 2, now perform extra unlock"); syncLock.Unlock(); Console.WriteLine("Successfully performed second unlock"); VerifyUnlocked(syncLock); } // Now test higher scale re-entrance Console.WriteLine("Testing locking {0} times on the same thread, then unlocking the same #", lockMax); if (!(syncLock is SimpleSpinLock)) { for (int lockCount = 0; lockCount < lockMax; lockCount++) { syncLock.Lock(); } for (int unlockCount = 0; unlockCount < lockMax; unlockCount++) { syncLock.Unlock(); } VerifyUnlocked(syncLock); } Console.WriteLine("Successfully verified lock re-entrance count for non-trivial number of re-entrant calls"); Console.WriteLine("Lock once, unlock twice -- this should fail"); syncLock.Lock(); syncLock.Unlock(); Exception unbalancedException = null; try { syncLock.Unlock(); } catch (InvalidOperationException e) { Console.WriteLine("Expected InvalidOperationException caught"); unbalancedException = e; } if (unbalancedException == null) { throw new InvalidOperationException("Lock should not allow unlock to be called twice after one call to lock"); } }
void VerifyUnlocked(ISyncLock syncLock) { InvalidOperationException tooManyUnlocksException = null; try { syncLock.Unlock(); } catch (InvalidOperationException e) { Console.WriteLine("Caught expected exception after unlocking too many times: {0}: {1}", e.GetType().ToString(), e.Message); tooManyUnlocksException = e; } if (tooManyUnlocksException == null) { throw new InvalidOperationException("Unlock should not have succeeded after being in what should have been an unlocked state"); } }
void TestLockWait(ISyncLock syncLock, TimeSpan waitBeforeCheckingLock, TimeSpan addtionalTimeBeforeRelease, bool waitForUnlock) { TimeSpan expectedWaitTime = new TimeSpan((long)(Math.Min(waitBeforeCheckingLock.Ticks, addtionalTimeBeforeRelease.Ticks))) + new TimeSpan(0,0,3); lockCheckReadyAcquired.Reset(); lockReleaseEvent.Reset(); variationCompleteEvent.Reset(); lockWaitTime = waitBeforeCheckingLock; // +waitBeforeCheckingLock; releaseDelay = addtionalTimeBeforeRelease; lockThread = new Thread(LockThreadFunction); lockThread.Start(syncLock); WaitForLockAcquisition(); // This should expire bool expired = ! syncLock.WaitForLock(new TimeSpan(0,0,0)); if (! expired) { throw new InvalidOperationException("Lock was released before expected, due to either lock defect or race conditions that should be rare"); } // Tell the other thread to release the lock lockReleaseEvent.Set(); DateTime waitStart = DateTime.UtcNow; if (waitForUnlock) { WaitForLockRelease(); } bool acquiredLock = syncLock.WaitForLock(lockWaitTime); DateTime waitEnd = DateTime.UtcNow; variationCompleteEvent.Set(); if (!acquiredLock) { if (waitForUnlock || ( waitBeforeCheckingLock > addtionalTimeBeforeRelease) ) { throw new InvalidOperationException("Unable to acquire lock within the specified timeout"); } else { Console.WriteLine("Wait for lock timed out as expected"); } } else { syncLock.Unlock(); if (waitBeforeCheckingLock < addtionalTimeBeforeRelease) { throw new InvalidOperationException("Wait did not time out as expected"); } else { Console.WriteLine("Wait was satisfied as expected"); } } TimeSpan duration = waitEnd - waitStart; Console.WriteLine("Expected wait time was {0} and actual time was {1}", expectedWaitTime, duration); if (duration > expectedWaitTime) { throw new InvalidOperationException(string.Format("Expected wait time was {0} and actual time was {1}", expectedWaitTime, duration)); } }
public abstract void RunTest(ISyncLock lockObject, TestParameters testParameters);
static ObjectLock() { stateLock = new SimpleSpinLock(); objectToLockMap = new Dictionary<object, ObjectLock>(); }