public void TestSynchronizedBlockWithInvalidUsage() { this.TestWithError(async() => { try { var monitor = SynchronizedBlock.Lock(new object()); // We yield to make sure the execution is asynchronous. await Task.Yield(); monitor.Pulse(); // We do not dispose inside a using statement, because the `SynchronizationLockException` // will trigger the disposal, which will fail because an await statement is not allowed // inside a synchronized block. The C# compiler normally prevents it when using the lock // statement, but we cannot prevent it when directly using the mock. monitor.Dispose(); } catch (SynchronizationLockException) { Specification.Assert(false, "Expected exception thrown."); } }, expectedError: "Expected exception thrown.", replay: true); }
internal void DoLock() { using (var monitor = SynchronizedBlock.Lock(this.SyncObject)) { Debug.WriteLine("Re-entered lock from the same task {0}.", GetCurrentTaskId()); } }
internal void Signal() { using (var monitor = SynchronizedBlock.Lock(this.SyncObject)) { this.Signalled = true; monitor.Pulse(); } }
internal void ReentrantWait() { Debug.WriteLine("Entering lock on task {0}.", GetCurrentTaskId()); using (var monitor = SynchronizedBlock.Lock(this.SyncObject)) { Debug.WriteLine("Entered lock on task {0}.", GetCurrentTaskId()); this.DoWait(); } }
public void TestSynchronizedBlockWithInvalidSyncObject() { this.TestWithException <ArgumentNullException>(() => { using (var monitor = SynchronizedBlock.Lock(null)) { } }, replay: true); }
internal void DoWait() { using (var monitor = SynchronizedBlock.Lock(this.SyncObject)) { Debug.WriteLine("Re-entered lock from the same task {0}.", GetCurrentTaskId()); Debug.WriteLine("Task {0} is now waiting...", GetCurrentTaskId()); this.Wait(); Debug.WriteLine("Task {0} received the signal.", GetCurrentTaskId()); } }
internal void Wait() { using (var monitor = SynchronizedBlock.Lock(this.SyncObject)) { while (!this.Signalled) { bool result = monitor.Wait(); Assert.True(result, "Wait returned false."); } } }
public void TestSynchronizedBlockWithInvalidPulseAllState() { this.TestWithException <SynchronizationLockException>(() => { SynchronizedBlock monitor; using (monitor = SynchronizedBlock.Lock(new object())) { } monitor.PulseAll(); }, replay: true); }
public void TestSynchronizedBlockWithAsyncExecution() { if (!this.IsSystematicTest) { return; } // We only test this without rewriting. With rewriting, we don't need to use synchronized block // and the compiler will make sure that an await cannot exist inside a lock block. this.TestWithError(async() => { using (var monitor = SynchronizedBlock.Lock(new object())) { // Normally, an await statement is not allowed inside a synchronized block. // The C# compiler normally prevents it when using the lock statement, but // we cannot prevent it when directly using the mock. Using it here fails // because `Dispose` is invoked from an asynchronized continuation. await Task.Yield(); } }, expectedError: "Cannot invoke Dispose without acquiring the lock.", replay: true); }