/// <summary> /// Runs all tests under each SyncBlk variation /// </summary> /// <param name="lockIsHeld">Whether to expect that the lock is being held (experiencing /// contention) while each lock attempt is performed</param> /// <param name="scenario">A lock contention scenario to run under each SyncBlk scenario. Is /// passed an object that may or may not have a SyncBlk, and a lock acquisition scenario to run /// under that level of contention</param> void SyncBlkVariants(LockIsHeld lockIsHeld, Action <object, Action <object> > scenario) { Console.WriteLine("Positive tests, no SyncBlk"); MethodVariants(lockIsHeld, delegate(Action <object> innerScenario) { object obj = new object(); scenario(obj, delegate(object o) { innerScenario(o); }); }); Console.WriteLine("Positive tests, with HashCode"); MethodVariants(lockIsHeld, delegate(Action <object> innerScenario) { object obj = new object(); obj.GetHashCode(); scenario(obj, delegate(object o) { innerScenario(o); }); }); Console.WriteLine("Positive tests, with SyncBlk"); MethodVariants(lockIsHeld, delegate(Action <object> innerScenario) { object obj = new object(); obj.GetHashCode(); Monitor.Enter(obj); Monitor.Exit(obj); scenario(obj, delegate(object o) { innerScenario(o); }); }); }
LockIsHeld Reverse(LockIsHeld lockIsHeld) { switch (lockIsHeld) { case LockIsHeld.Yes: return(LockIsHeld.No); case LockIsHeld.No: return(LockIsHeld.Yes); default: return(lockIsHeld); } }
void AssertTookLockAndRelease(LockIsHeld expected, object obj, bool tookLock) { Assert((expected == LockIsHeld.Yes && tookLock) || (expected == LockIsHeld.No && !tookLock) || expected == LockIsHeld.Maybe); if (tookLock) { Assert(!inContention); } bool exitFailed = false; try { Monitor.Exit(obj); } catch (SynchronizationLockException) { exitFailed = true; } Assert(tookLock == !exitFailed); }
/// <summary> /// Runs all lock acquisition scenarios inside of an outer contention/SyncBlk scenario /// </summary> /// <param name="lockIsHeld">whether to expect the lock to be held when we try to acquire it</param> /// <param name="scenario">The contention/SyncBlk scenario to run each acquisition scenario inside of.</param> void MethodVariants(LockIsHeld lockIsHeld, Action <Action <object> > scenario) { bool tookLock; scenario(delegate(object obj) { Monitor.Enter(obj); AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); }); scenario(delegate(object obj) { tookLock = false; Monitor.Enter(obj, ref tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); }); scenario(delegate(object obj) { tookLock = Monitor.TryEnter(obj); AssertTookLockAndRelease(Reverse(lockIsHeld), obj, tookLock); }); scenario(delegate(object obj) { tookLock = Monitor.TryEnter(obj, 0); AssertTookLockAndRelease(Reverse(lockIsHeld), obj, tookLock); }); scenario(delegate(object obj) { DateTime start = DateTime.Now; tookLock = Monitor.TryEnter(obj, 10000); double elapsed = (DateTime.Now - start).TotalSeconds; AssertTookLockAndRelease(elapsed < 5.0 ? LockIsHeld.Yes : LockIsHeld.Maybe, obj, tookLock); }); scenario(delegate(object obj) { tookLock = Monitor.TryEnter(obj, Timeout.Infinite); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); }); scenario(delegate(object obj) { tookLock = Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(0)); AssertTookLockAndRelease(Reverse(lockIsHeld), obj, tookLock); }); scenario(delegate(object obj) { tookLock = Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(10000)); AssertTookLockAndRelease(LockIsHeld.Maybe, obj, tookLock); }); scenario(delegate(object obj) { tookLock = Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(Timeout.Infinite)); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, ref tookLock); AssertTookLockAndRelease(Reverse(lockIsHeld), obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, 0, ref tookLock); AssertTookLockAndRelease(Reverse(lockIsHeld), obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, 10000, ref tookLock); AssertTookLockAndRelease(LockIsHeld.Maybe, obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, Timeout.Infinite, ref tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(0), ref tookLock); AssertTookLockAndRelease(Reverse(lockIsHeld), obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(10000), ref tookLock); AssertTookLockAndRelease(LockIsHeld.Maybe, obj, tookLock); }); scenario(delegate(object obj) { tookLock = false; Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(Timeout.Infinite), ref tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); }); if (lockIsHeld == LockIsHeld.No) { scenario(delegate(object obj) { Monitor.Enter(obj); Monitor.Enter(obj); AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.No, obj, false); }); scenario(delegate(object obj) { Monitor.Enter(obj); tookLock = false; Monitor.Enter(obj, ref tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.No, obj, false); }); scenario(delegate(object obj) { Monitor.Enter(obj); tookLock = false; Monitor.TryEnter(obj, ref tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, tookLock); AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.No, obj, false); }); scenario(delegate(object obj) { Monitor.Enter(obj); for (int i = 0; i < 70; i++) { Monitor.Enter(obj); } for (int i = 0; i < 70; i++) { AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); } AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.No, obj, false); }); scenario(delegate(object obj) { Monitor.Enter(obj); for (int i = 0; i < 70; i++) { tookLock = false; Monitor.Enter(obj, ref tookLock); Assert(tookLock); } for (int i = 0; i < 70; i++) { AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); } AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.No, obj, false); }); scenario(delegate(object obj) { Monitor.Enter(obj); for (int i = 0; i < 70; i++) { tookLock = false; Monitor.TryEnter(obj, ref tookLock); Assert(tookLock); } for (int i = 0; i < 70; i++) { AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); } AssertTookLockAndRelease(LockIsHeld.Yes, obj, true); AssertTookLockAndRelease(LockIsHeld.No, obj, false); }); } }