public void ReadersMayBeConcurrent() { using (Barrier barrier = new Barrier(2)) using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim()) { Assert.AreEqual(0, rwls.CurrentReadCount); Task.WaitAll( Task.Run(() => { rwls.EnterReadLock(); barrier.SignalAndWait(); // 1 Assert.IsTrue(rwls.IsReadLockHeld); barrier.SignalAndWait(); // 2 Assert.AreEqual(2, rwls.CurrentReadCount); barrier.SignalAndWait(); // 3 barrier.SignalAndWait(); // 4 rwls.ExitReadLock(); }), Task.Run(() => { barrier.SignalAndWait(); // 1 rwls.EnterReadLock(); barrier.SignalAndWait(); // 2 Assert.IsTrue(rwls.IsReadLockHeld); Assert.AreEqual(0, rwls.WaitingReadCount); barrier.SignalAndWait(); // 3 rwls.ExitReadLock(); barrier.SignalAndWait(); // 4 })); Assert.AreEqual(0, rwls.CurrentReadCount); } }
public void DeadlockAvoidance() { using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim()) { rwls.EnterReadLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterReadLock()); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterUpgradeableReadLock()); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterWriteLock()); rwls.ExitReadLock(); rwls.EnterUpgradeableReadLock(); rwls.EnterReadLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterReadLock()); rwls.ExitReadLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterUpgradeableReadLock()); rwls.EnterWriteLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterWriteLock()); rwls.ExitWriteLock(); rwls.ExitUpgradeableReadLock(); rwls.EnterWriteLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterReadLock()); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterUpgradeableReadLock()); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterWriteLock()); rwls.ExitWriteLock(); } using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion)) { rwls.EnterReadLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterWriteLock()); rwls.EnterReadLock(); AssertExtensions.Throws <LockRecursionException>(() => rwls.EnterUpgradeableReadLock()); rwls.ExitReadLock(); rwls.ExitReadLock(); rwls.EnterUpgradeableReadLock(); rwls.EnterReadLock(); rwls.EnterUpgradeableReadLock(); rwls.ExitUpgradeableReadLock(); rwls.EnterReadLock(); rwls.ExitReadLock(); rwls.ExitReadLock(); rwls.EnterWriteLock(); rwls.EnterWriteLock(); rwls.ExitWriteLock(); rwls.ExitWriteLock(); rwls.ExitUpgradeableReadLock(); rwls.EnterWriteLock(); rwls.EnterReadLock(); rwls.ExitReadLock(); rwls.EnterUpgradeableReadLock(); rwls.ExitUpgradeableReadLock(); rwls.EnterWriteLock(); rwls.ExitWriteLock(); rwls.ExitWriteLock(); } }
public void Dispose() { ReaderWriterLockSlim rwls; rwls = new ReaderWriterLockSlim(); rwls.Dispose(); AssertExtensions.Throws <ObjectDisposedException>(() => rwls.TryEnterReadLock(0)); AssertExtensions.Throws <ObjectDisposedException>(() => rwls.TryEnterUpgradeableReadLock(0)); AssertExtensions.Throws <ObjectDisposedException>(() => rwls.TryEnterWriteLock(0)); rwls.Dispose(); for (int i = 0; i < 3; i++) { rwls = new ReaderWriterLockSlim(); switch (i) { case 0: rwls.EnterReadLock(); break; case 1: rwls.EnterUpgradeableReadLock(); break; case 2: rwls.EnterWriteLock(); break; } AssertExtensions.Throws <SynchronizationLockException>(() => rwls.Dispose()); } }
public void EnterExit() { using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim()) { Assert.IsFalse(rwls.IsReadLockHeld); rwls.EnterReadLock(); Assert.IsTrue(rwls.IsReadLockHeld); rwls.ExitReadLock(); Assert.IsFalse(rwls.IsReadLockHeld); Assert.IsFalse(rwls.IsUpgradeableReadLockHeld); rwls.EnterUpgradeableReadLock(); Assert.IsTrue(rwls.IsUpgradeableReadLockHeld); rwls.ExitUpgradeableReadLock(); Assert.IsFalse(rwls.IsUpgradeableReadLockHeld); Assert.IsFalse(rwls.IsWriteLockHeld); rwls.EnterWriteLock(); Assert.IsTrue(rwls.IsWriteLockHeld); rwls.ExitWriteLock(); Assert.IsFalse(rwls.IsWriteLockHeld); Assert.IsFalse(rwls.IsUpgradeableReadLockHeld); rwls.EnterUpgradeableReadLock(); Assert.IsFalse(rwls.IsWriteLockHeld); Assert.IsTrue(rwls.IsUpgradeableReadLockHeld); rwls.EnterWriteLock(); Assert.IsTrue(rwls.IsWriteLockHeld); rwls.ExitWriteLock(); Assert.IsFalse(rwls.IsWriteLockHeld); Assert.IsTrue(rwls.IsUpgradeableReadLockHeld); rwls.ExitUpgradeableReadLock(); Assert.IsFalse(rwls.IsUpgradeableReadLockHeld); Assert.IsTrue(rwls.TryEnterReadLock(0)); rwls.ExitReadLock(); Assert.IsTrue(rwls.TryEnterReadLock(Timeout2.InfiniteTimeSpan)); rwls.ExitReadLock(); Assert.IsTrue(rwls.TryEnterUpgradeableReadLock(0)); rwls.ExitUpgradeableReadLock(); Assert.IsTrue(rwls.TryEnterUpgradeableReadLock(Timeout2.InfiniteTimeSpan)); rwls.ExitUpgradeableReadLock(); Assert.IsTrue(rwls.TryEnterWriteLock(0)); rwls.ExitWriteLock(); Assert.IsTrue(rwls.TryEnterWriteLock(Timeout2.InfiniteTimeSpan)); rwls.ExitWriteLock(); } }
public void WriterToReaderChain() { using (AutoResetEvent are = new AutoResetEvent(false)) using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim()) { rwls.EnterWriteLock(); Task t = Task.Factory.StartNew(() => { Assert.IsFalse(rwls.TryEnterReadLock(TimeSpan.FromMilliseconds(10))); Task.Run(() => are.Set()); // ideally this won't fire until we've called EnterReadLock, but it's a benign race in that the test will succeed either way rwls.EnterReadLock(); rwls.ExitReadLock(); }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); are.WaitOne(); rwls.ExitWriteLock(); t.GetAwaiter().GetResult(); } }
//[Theory] //[InlineData(LockRecursionPolicy.NoRecursion)] //[InlineData(LockRecursionPolicy.SupportsRecursion)] private static void InvalidExits(LockRecursionPolicy policy) { using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim(policy)) { AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitReadLock()); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitUpgradeableReadLock()); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitWriteLock()); rwls.EnterReadLock(); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitUpgradeableReadLock()); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitWriteLock()); rwls.ExitReadLock(); rwls.EnterUpgradeableReadLock(); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitReadLock()); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitWriteLock()); rwls.ExitUpgradeableReadLock(); rwls.EnterWriteLock(); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitReadLock()); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitUpgradeableReadLock()); rwls.ExitWriteLock(); using (Barrier barrier = new Barrier(2)) { Task t = Task.Factory.StartNew(() => { rwls.EnterWriteLock(); barrier.SignalAndWait(); barrier.SignalAndWait(); rwls.ExitWriteLock(); }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); barrier.SignalAndWait(); AssertExtensions.Throws <SynchronizationLockException>(() => rwls.ExitWriteLock()); barrier.SignalAndWait(); t.GetAwaiter().GetResult(); } } }
//[OuterLoop] public void DontReleaseWaitingReadersWhenThereAreWaitingWriters() { using (var rwls = new ReaderWriterLockSlim()) { rwls.EnterUpgradeableReadLock(); rwls.EnterWriteLock(); // Typical order of execution: 0 // Add a waiting writer var threads = new Thread[2]; using (var beforeEnterWriteLock = new ManualResetEvent(false)) { var thread = new Thread(() => { beforeEnterWriteLock.Set(); rwls.EnterWriteLock(); // Typical order of execution: 3 rwls.ExitWriteLock(); }); thread.IsBackground = true; thread.Start(); threads[0] = thread; beforeEnterWriteLock.WaitOne(); } // Add a waiting reader using (var beforeEnterReadLock = new ManualResetEvent(false)) { var thread = new Thread(() => { beforeEnterReadLock.Set(); rwls.EnterReadLock(); // Typical order of execution: 4 rwls.ExitReadLock(); }); thread.IsBackground = true; thread.Start(); threads[1] = thread; beforeEnterReadLock.WaitOne(); } // Wait for the background threads to block waiting for their locks Thread.Sleep(1000); // Typical order of execution: 1 rwls.ExitWriteLock(); // At this point there is still one reader and one waiting writer, so the reader-writer lock should not try to // release any of the threads waiting for a lock // Typical order of execution: 2 rwls.ExitUpgradeableReadLock(); // At this point, the waiting writer should be released, and the waiting reader should not foreach (var thread in threads) { thread.Join(); } // Typical order of execution: 5 } }
//[OuterLoop] //[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Hangs in desktop, issue dotnet/corefx#3364 is not fixed there")] public void ReleaseReadersWhenWaitingWriterTimesOut() { using (var rwls = new ReaderWriterLockSlim()) { // Enter the read lock rwls.EnterReadLock(); // Typical order of execution: 0 Thread writeWaiterThread; using (var beforeTryEnterWriteLock = new ManualResetEvent(false)) { writeWaiterThread = new Thread(() => { // Typical order of execution: 1 // Add a writer to the wait list for enough time to allow successive readers to enter the wait list while this // writer is waiting beforeTryEnterWriteLock.Set(); if (rwls.TryEnterWriteLock(1000)) { // The typical order of execution is not guaranteed, as sleep times are not guaranteed. For // instance, before this write lock is added to the wait list, the two new read locks may be // acquired. In that case, the test may complete before or while the write lock is taken. rwls.ExitWriteLock(); } // Typical order of execution: 4 }); writeWaiterThread.IsBackground = true; writeWaiterThread.Start(); beforeTryEnterWriteLock.WaitOne(); } Thread.Sleep(500); // wait for TryEnterWriteLock to enter the wait list // A writer should now be waiting, add readers to the wait list. Since a read lock is still acquired, the writer // should time out waiting, then these readers should enter and exit the lock. ThreadStart EnterAndExitReadLock = () => { // Typical order of execution: 2, 3 rwls.EnterReadLock(); // Typical order of execution: 5, 6 rwls.ExitReadLock(); }; var readerThreads = new Thread[] { new Thread(EnterAndExitReadLock), new Thread(EnterAndExitReadLock) }; foreach (var readerThread in readerThreads) { readerThread.IsBackground = true; readerThread.Start(); } foreach (var readerThread in readerThreads) { readerThread.Join(); } rwls.ExitReadLock(); // Typical order of execution: 7 writeWaiterThread.Join(); } }