if (!ctstate.LockState.Has (LockState.Read))
throw new SynchronizationLockException ("The current thread has not entered the lock in read mode");
- ctstate.LockState ^= LockState.Read;
- --ctstate.ReaderRecursiveCount;
- if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
- readerDoneEvent.Set ();
+ if (--ctstate.ReaderRecursiveCount == 0) {
+ ctstate.LockState ^= LockState.Read;
+ if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+ readerDoneEvent.Set ();
+ }
}
}
if (!ctstate.LockState.Has (LockState.Write))
throw new SynchronizationLockException ("The current thread has not entered the lock in write mode");
- bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
- ctstate.LockState ^= LockState.Write;
- --ctstate.WriterRecursiveCount;
-
- int value = Interlocked.Add (ref rwlock, isUpgradable ? RwRead - RwWrite : -RwWrite);
- writerDoneEvent.Set ();
- if (isUpgradable && value >> RwReadBit == 1)
- readerDoneEvent.Reset ();
+ if (--ctstate.WriterRecursiveCount == 0) {
+ bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
+ ctstate.LockState ^= LockState.Write;
+
+ int value = Interlocked.Add (ref rwlock, isUpgradable ? RwRead - RwWrite : -RwWrite);
+ writerDoneEvent.Set ();
+ if (isUpgradable && value >> RwReadBit == 1)
+ readerDoneEvent.Reset ();
+ }
}
}
if (!ctstate.LockState.Has (LockState.Upgradable | LockState.Read))
throw new SynchronizationLockException ("The current thread has not entered the lock in upgradable mode");
- upgradableTaken.Value = false;
- upgradableEvent.Set ();
+ if (--ctstate.UpgradeableRecursiveCount == 0) {
+ upgradableTaken.Value = false;
+ upgradableEvent.Set ();
- ctstate.LockState ^= LockState.Upgradable;
- --ctstate.UpgradeableRecursiveCount;
- if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
- readerDoneEvent.Set ();
+ ctstate.LockState ^= LockState.Upgradable;
+ if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+ readerDoneEvent.Set ();
+ }
}
}
Assert.AreEqual (false, wLock, "#1b");
Assert.AreEqual (0, rWrite, "#3b");
}
+
+ [Test]
+ public void RecursiveEnterExitReadTest ()
+ {
+ var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
+
+ v.EnterReadLock ();
+ v.EnterReadLock ();
+ v.EnterReadLock ();
+
+ Assert.IsTrue (v.IsReadLockHeld);
+ Assert.AreEqual (3, v.RecursiveReadCount);
+
+ v.ExitReadLock ();
+
+ Assert.IsTrue (v.IsReadLockHeld);
+ Assert.AreEqual (2, v.RecursiveReadCount);
+ }
+
+ [Test]
+ public void RecursiveEnterExitWriteTest ()
+ {
+ var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
+
+ v.EnterWriteLock ();
+ v.EnterWriteLock ();
+ v.EnterWriteLock ();
+
+ Assert.IsTrue (v.IsWriteLockHeld);
+ Assert.AreEqual (3, v.RecursiveWriteCount);
+
+ v.ExitWriteLock ();
+ v.ExitWriteLock ();
+
+ Assert.IsTrue (v.IsWriteLockHeld);
+ Assert.AreEqual (1, v.RecursiveWriteCount);
+ }
+
+ [Test]
+ public void RecursiveEnterExitUpgradableTest ()
+ {
+ var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
+
+ v.EnterUpgradeableReadLock ();
+ v.EnterUpgradeableReadLock ();
+ v.EnterUpgradeableReadLock ();
+
+ Assert.IsTrue (v.IsUpgradeableReadLockHeld);
+ Assert.AreEqual (3, v.RecursiveUpgradeCount);
+
+ v.ExitUpgradeableReadLock ();
+
+ Assert.IsTrue (v.IsUpgradeableReadLockHeld);
+ Assert.AreEqual (2, v.RecursiveUpgradeCount);
+ }
}
}