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 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();
            }
        }
        //[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();
                }
            }
        }
 public void WriterToUpgradeableReaderChain()
 {
     using (AutoResetEvent are = new AutoResetEvent(false))
         using (ReaderWriterLockSlim rwls = new ReaderWriterLockSlim())
         {
             rwls.EnterWriteLock();
             Task t = Task.Factory.StartNew(() =>
             {
                 Assert.IsFalse(rwls.TryEnterUpgradeableReadLock(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.EnterUpgradeableReadLock();
                 rwls.ExitUpgradeableReadLock();
             }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
             are.WaitOne();
             rwls.ExitWriteLock();
             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
            }
        }